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 : m_abdurohman@yahoo.com.
Bandung, 27-Agustus 2002
Penulis
DAFTAR ISI
Kata Pengantar
Daftar Isi
1. Pengenalan 1
1.1. Pendahuluan 1
1.2. Representasi Data 3
1.3. Bahasa Assembly – Pengenalan 8
1.4. Elemen Dasar Bahasa Assembly 10
1.5. Contoh Program Hello 13
2. Arsitektur Perangkat Keras dan Perangkat lunak. 15
2.1. Komponen Mikrokomputer 15
2.2. Arsitektur Sistem 17
2.3. Perangkat Lunak Sistem dan Memori 26
3. Dasar-Dasar Bahasa Assembly 29
3.1. Perintah Definisi Data 29
3.2. Instruksi Transfer Data 34
3.3. Instruksi Aritmetik 37
3.4. Mode Pengalamatan 40
3.5. Struktur Program 46
4. Layanan Masukan/Keluaran (Input/Output) 49
4.1. Prosedur 49
4.2. Interrupt Perangkat Lunak 52
4.3. Fungsi Call DOS 54
4.4. Kendali Video Level Bios (INT 10h) 59
5. Pemrosesan Kondisi 61
5.1. Boolean dan Instruksi Perbandingan 61
5.2. Loncat Kondisional 67
5.3. Liupan Kondisional (Conditional Loops) 72
5.4. Struktur Logic Tingkat Tinggi 73
6. Aritmetika 78
6.1. Instruksi Gser (Shift) dan Putar (Rotate) 78
6.2. Aplikasi Contoh 82
6.3. Multi - Penjumlahan dan Pengurangan
(Multiple Addition and Substraction) 85
6.4. Perkalian dan Pembagian 87
7. Makro dan Struktur 93
7.1. Pengenalan 93
7.2. Teknik Khusus 102
7.3. Operator Makro 107
7.4. Library Makro 109
7.5. Penggunaan Makro Lebih Lanjut 112
7.6. Operator dan Perintah Lanjut 122
7.7. Contoh Penggunaan Macro Dalam Program 129
8. Hubungan Dengan Bahasa Tingkat Tinggi 136
8.1. Hubungan Dengan Turbo Pascal 136
8.2. Turbo Built-In Assembler (BASM) 145
8.3. Pernyataan dan Perintah Inline 148
8.4. Antarmuka Turbo Assembler dengan Turbo Pascal 149
8.5. Hubungan dengan Turbo C 158
8.6. 8. 6. Antarmuka Turbo Assembler Dengan Borland C++ 162
9. Contoh Program 169
10. Daftar Pustaka 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 Basis / radix Digit yang mungkin
Biner 2 01
Oktal 8 01234567
Desimal 10 0123456789
Heksadesimal 16 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 Bit Range (bawah-atas)
Byte 8 0-225
Word 16 0-65,535
Double word 32 0-4,294,967,295
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 26 25 24 23 22 21 20
Nilai 128 64 32 16 8 4 2 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 1 0 0 1
Desimal 8 1 = 9 d
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 0110 0000 0111 1001 0100
1 6 0 7 9 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 Desimal Heksadesimal
0000 0 0
0001 1 1
0010 2 2
0011 3 3
0100 4 4
0101 5 5
0110 6 6
0111 7 7
1000 8 8
1001 9 9
1010 10 A
1011 11 B
1100 12 C
1101 13 D
1110 14 E
1111 15 F
Posisi digit heksadesimal. Setiap posisi digit heksadesimal mewakili bilangan
pangkat dari 16.
163 162 161 160
Nilai 4096 256 16 1
Bilangan dapat dikonversi dari heksadesimal ke desimal dengan mengalikan
masing-masing digit dengan nilai posisinya. Misalnya bilangan 3BA4h, hasilnya
3 B A 4
Nilai posisi 4096 256 16 1
Hasil kali 12,288 2,816 160 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 (bilangan negatif)
00001010 (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 :
1 1 1 1 1 0 1 0 - 6
0 0 0 0 0 1 0 1 ones complement
+ 1 tambah 1
0 0 0 0 0 1 1 0 + 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 Nilai terendah Nilai tertinggi
Byte -127 +127
Word -32,767 +32,767
Double word -2,147,483,647 +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 Ctrl Mnemonic Penjelasan
00 NUL Karakter kosong
01 Ctrl – A SOH Awal header
02 Ctrl – B STX Awal teks
03 Ctrl – C ETX Akhir teks
04 Ctrl – D EOT Akhir transmisi
05 Ctrl – E ENQ Pertanyaan (Enquiry)
06 Ctrl – F ACK Pemberitahuan
07 Ctrl – G BEL Bel
08 Ctrl – H BS Backspace
09 Ctrl – I HT Tab horison
0A Ctrl – J LF Line feed
0B Ctrl – K VT Tab vertikal
0C Ctrl – L FF Form feed
0D Ctrl – M CR Carriage return
0E Ctrl – N SO Shift out
0F Ctrl – O SI Shift in
10 Ctrl – P DLE Data link escape
11 Ctrl – Q DC1 Device control 1
12 Ctrl – R DC2 Device control 2
13 Ctrl – S DC3 Device control 3
14 Ctrl – T DC4 Device control 4
15 Ctrl – U NAK Pemberitahuan negatif
16 Ctrl – V SYN Synchronous idle
17 Ctrl – W ETB Akhir transmisi blok
18 Ctrl – X CAN Batal
19 Ctrl – Y EM Akhir medium
1A Ctrl – Z SUB Pengurangan
(substitusi)
1B Ctrl – [ ESC Escape
1C Ctrl – \ FS Pemisah file
1D Ctrl – ] GS Pemisah grup
1E Ctrl – ^ RS Pemisah rekord
1F Ctrl – -| US 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 B C 1 2 3
Kode ASCII 41h 42h 43h 30h 31h 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 ; hanya sebuah mnemonic
inc ax ; operand tunggal
mov ax, bx ; 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 (nilai immediate)
count (variabel)
AX (register)
[0200] (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 ; memindahkan 5 ke dalam register ax
add ax, 10 ; menambahkan nilai 10h terhadap register ax
add ax, 20 ; menambahkan nilai 20h terhadap register ax
mov sum, ax ; menyimpan ax dalam variabel sum
int 20 ; 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
A 100
Mov ax, 5
Add ax, 10
Add ax, 20
Mov [0120] , ax
Int 20
R
T
T
T
G
Q
Assembly dimulai pada lokasi 100h
Perintah program yang pertama
Hasil jumlah pada lokasi 0120h
Akhir program
(tekan Enter untuk mengakhiri assembly)
Menampilkan register
Trace satu instruksi
Ekseskusi sisa program
Keluar dari Debug kembali ke DOS
Setelah isntruksi yang kedua akan diperoleh tampilan hasil sebagai berikut :
1. mov ax, 5 ax : 05
2. add ax, 10 ax : 10
3. add ax, 20 ax : 35
4. mov sum, ax ax : 35 sum : 35
AX = 0015 BX = 0000 CX = 0000 DX = 0000 SP = FFEE
BP = 0000 SI = 0000 DI = 0000 DS = 23AD ES = 23AD
SS = 23AD CS = 23AD IP = 0106 NV UP EI PL NZ NA PO NC
23AD : 0106 052000 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 Radix
11110000b
200
300d
4A6Bh
2047q
2047o
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 Penjelasan
A … Z, a … z
0 … 9
?
_
@
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 ; variabel (alokasi memori)
Count2 equ 100 ; 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 [1]
[2]
; program ini menampilkan pesan “Hello, world” [3]
[4]
dosseg [5]
. model small [6]
. stack 100h [7]
[8]
. data [9]
. hello_message db ‘Hello, world !’, 0dh, 0ah, ‘$’ [10]
[11]
. code [12]
main proc [13]
mov ax, @data [14]
mov ds, ax [15]
[16]
mov ah, 9 [17]
mov dx, offset hello_message [18]
int 21h [19]
[20]
mov ax, 4000h [21]
int 21h [22]
main endp [23]
endp main [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 386-
compatible 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.
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
200-watt
power
suplay
Half-height
200-MB
HD
CPU
32-bit
memori
expansion
slot
Internal
2400-baud
modem
16-bit VGA
video
controller
Serial and
Parallel port
Bus mouse
controller
External tape
backup connector
Hard disk and
ploppy disk
controller
Keyboard
connector
Intel 80386 DX
processor
Intel 80387 math
coproscessor
2-MB Ram on
system board
ROM BIOS
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)
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.
Register Data
Register Alamat
Unit Kendali
(control unit)
Arithmetic
Logic Unit
Register
Flag
Jalur keluaran
Jalur keluaran
Bus Alamat
Bus Data
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)
Register segemn CS, DS, SS, ES
Register indeks SI, DI, BP
Register khusus IP, SP
Register flag overflow, direction, interupt, tmp, sign, zero, auxiliary
carry, parity, carry.
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.
Instruksi mungkin menunjuk 16 bit atau 18 bit register data dari daftar berikut :
16-bit register AX
Register AH Register AL
Bit 15 ………… …………..0
Bit 7 ……………..0 7 …………..0
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
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.
AX
AH AL
BX
BH BL
CX
CH CL
DX
DH DL
Flag
IP
BP
SP
SI
DI
CS
SS
DS
ES
Segmen
Index
Status dan Kendali
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 S Z x A x P x C
O = Overflow S = Sign
D = Directione Z = Zero
I = Interrupt A = Auxiliary Carry
T = Trap P = Parity
X = tidak terdefinisi 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
|-------AX -----|
EAX
31 ………………………….0
|-------BX -----|
EBX
31 ………………………….0
|-------CX -----|
ECX
31 ………………………….0
|-------DX -----|
EDX
31 ………………………….0
|-----FLAG----|
EFLAG
Status dan Kendali
EBP
ESP
ESI
EDI
CS
SS
DS
ES
FS
GS }
Code Stack
Data
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
31 ………………………….0
|------- IP ------|
EIP
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.
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.
0006
SP
Sebelum
(high memory)
(low memory)
0006
00A5
SP
Sesudah
(high memory)
(low memory)
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 :
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 :
0006
00A5
0001
0002
SP
Sesudah
(high memory)
(low memory)
0006
00A5
0001
0002 SP
Sebelum
(high memory)
0006
00A5
0001
(0002)
SP
Sesudah
(high memory)
(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 :
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
Interrupt Vector Table
DOS data area
Software BIOS
DOS kernel, Device Driver, Etc
Bagian Resident COMMAND.COM
Bagian Transient COMMAND.COM
EGA/VGA Graphics Buffer
MDA Text Buffer
CGA/EGA/VGA Text Buffer
Reserved
ROM BIOS
00000
00400
9FFFF
A0000
B0000
B8000
C0000
FFFFF
Alamat (hex)
640 K RAM
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)
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 Byte Atribut
DB Define byte 1 Byte
DW Define word 2 Word
DD Define doubleword 4 Dobleword
DF, DP Define far pointer 6 Far pointer
DQ Define quadword 8 Quadword
DT Define tenbytes 10 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 :
A B C D
1 2 3 4
Deklarasi
AList db ‘ABCD’
Isi
Offset
Disimpan sebagai
char db ‘A’
signed1 db -128
signed2 db +127
unsigned1 db 0
unsigned2 db 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 db 10, 32, 41h, 00100010b
list2 db 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 : value1 dw 2AB6h
Penyimpanan :
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 dw 256, 257, 258, 259
P dw list
P2 dw P
aProc dw 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, 4-
byte 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 dd -2147483648
far_pointer1 dd ?
far_pointer2 dd 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) ; 20 byte semuanya sama dengan nol
db 20 dup (?) ; 20 byte tidak diinisialisasi
db 4 dup (‘ABC’) ; 12 byte : “ABCABCABCABC”
db 4096 dup (0) ; 4096-byte , semuanya nol
dw 5 dup (1000h) ; 5 word, masing-masing sama dengan nol
dw 5 dup (?) ; 5 word, tidak diinisialisasi
dd 100h dup(?) ; 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 ; error : ukuran operand harus cocok
…
….
count dw 20h
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 ; ip sebagai tujuan
mov ds, 1000h ; immediate ke segmen
mov ds, es ; segmen ke segmen
mov al, bx ; ukuran operan tidak sama
mov si, al ; ukuran operan tidak sama
mov word_1, al ; ukuran operan tidak sama
mov 1000h, ax ; immediate sebagai tujuan
mov word_2, word_1 ; memori ke memori
…
…
word_1 dw 1000h
word_2 dw 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 ; isi = 10
mov dl, array+1 ; isi = 20
mov dh, array+4 ; 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 8-
bit 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 01111110
add al, 2 + 00000010
10000000 AL = -128 ?, OF =1
Contoh 2 :
mov al, -128 10000000
sub al, 2 - 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
Mode Contoh Keterangan
Direct Op1
bytelist
[200]
Alamat efektif adalah
displacement
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 Ukruan (bit)
10
‘A’
‘AB’
65535
(2+3)/5
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 ; BX = 0200
add bx, 5 ; BX = 0205
mov dl, [bx] ; DL = ‘F’
Ilustrasi
0200
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]
A B C D E F G … … …
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 :
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
02 16 04 22 13 19 42 … … …
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] ; salah : dua register basis
mov ax, [si-di] ; 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
[BX] [SI]
10 20 30 40 50 60 70 80 90 … … …
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 MASM
tasm hello; masm hello;
tlink 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 [1]
[2]
; program ini menampilkan pesan “Hello, world” [3]
[4]
dosseg [5]
. model small [6]
. stack 100h [7]
[8]
. data [9]
. hello_message db ‘Hello, world !’, 0dh, 0ah, ‘$’ [10]
[11]
. code [12]
main proc [13]
mov ax, @data [14]
mov ds, ax [15]
[16]
mov ah, 9 [17]
mov dx, offset hello_message [18]
int 21h [19]
[20]
mov ax, 4000h [21]
int 21h [22]
main endp [23]
endp main [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 Penjelasan
Tiny
Small
Medium
Compact
Large
Huge
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 Stop Length Name Class
00000H 00010H 00011H _TEXT CODE
00020H 0002FH 00010H _DATA DATA
00030H 0012FH 00100H STACK STACK
Diagram segmen :
Misalkan program diload pada alamat absolut 20000 :
Segmen Alamat Absolut Nilai Register Segmen
Code 20000 2000
(20h 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.
Data 20020 2002
(10h byte)
Stack 20030 2003
(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
instruksi call menyimpan offset 0009 ke
dalam stack, dan memindahkan 0080 ke
dalam IP.
Stack
0000
0009 0009 dimasukan ke dalam stack
Subrutin
Subroutine1 proc
0080 mov ax,1
…
…
…
Subroutine1 endp
Instruksi RET mengambil 0009 dari
stack dan menyimpannya dalam
register IP. Ini menyebabkan CPU
melanjutkan eksekusi offset 0009.
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
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.
Stack
0000
2FC0 CS dan IP dimasukan
0009 ke dalam stack
Subrutin
Subroutine1 PROC FAR
3AB6 : 0080 mov ax, 1
…
…
ret
subroutine1 endp
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 segemen kembali dan nilai offset
0009 yang dipop ke dalam CS dan IP
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.
…
mov …
int 10h
add …
…
Program
pemanggil
… 3069 F000:F065 F000 : AB62 …
sti
cld
push es
push ds
…
IRET
Penanganan
interrupt
F000 : F065
F066
F067
…
Kembali ke
pemanggil
1
2
3
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 Penjelasan
0 Menghentikan program yang sedang dijalankan
1 Input konsol dengan echo. Menunggu karekter dari perangkat input
standar. Karaker dikembalikan ke dalam AL dan ditampilkan. Dapat
dihentikan denagn CTRL-BREAK.
2 Keluaran karakter. Mengirim karakter dalam DL ke perangkat keluaran
standar (konsol).
3 Input bantu. Menunggu karakter dari asynchronous port. Karakter
dikembalikan dalam AL (jarang digunakan).
4 Output bantu. Mengirim karakter dalam DL ke asynchronous port
(jarang digunakan).
5 Output printer. Mengirim karakter dalam DALAM ke port printer
parallel.
6 I/O konsol langsung. Melakukan input karakter yang tersedia dari
perangkat input standar atau mengirim karakter ke output standar.
Kendali karakter tidak difilter.
7 Input konsol. Menunggu karakter dari perangkat input standar.
Karakter dikembalikan ke dalam AL, tapi tidak ditampilkan di konsol.
Kendali karakter tidak difilter.
8 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.
9 Output string. Mengirim string karakter dari perangkat input standar.
DX mengandung offset string.
0A Input buffer. Menunggu string karakter dari perangkat input standar.
Karakter disimpan dalam buffer yang diacu oleh DX.
0B Mengambil status input konsol. Memeriksa apakah karakter input
menunggu. Mengembalikan AL = 0FFh jika karakter siap dan AL = 0
jika tidak.
0C 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.
Nomor fungsi DOS
1 6 7 8
Wait ? Y N Y Y
Echo ? Y N N N
Ctrl-Break ? Y N N Y
Filter ? Y N N 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 :
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 my name is
4B 69 70 20 49 72 76 69 6E 65 0D Kip Irvine
Enter
n m
0 1 2 3 4 … n+1
Jumlah maksimum
karakter yang
diijinkan
Jumlah karakter yang
bernar-benar
diinputkan
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 Penjelasan
1 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.
2 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.
3 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
4 Set typematic repeat rate.
5 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 Penjelasan
0 Set mode video
1 Set baris kursor
2 Set posisi kursor
3 Mengambil posisi kursor
4 Membaca pen terang
5 Set halaman tampilan
6 Geser window keatas
7 Geser window kebawah
8 Membaca karakter dan atribut
9 Menulis karakter dan atribut
0Ah Menulis karakter
0Bh Set palet warna
0Ch Menulis titik
0Dh Membaca titik
0Eh Menulis karakter
0Fh Mengambil mode video
11h 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 Komentar
AND Menghasilkan 1 jika kedua bit inputnya bernilai 1
ORANG Menghasilkan 1 jika salah satu inputnya bernilai 1
XOR Menghasilkan 1 jika kedua inputnya berbeda (disebut exclusive-OR)
NOT 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 :
mov cx, 10000
L1 : 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 :
0 0 1 1
OR 0 1 0 1
Hasil 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 00000101 (05h)
boolean OR 00110000 (30h)
hasil : 00110101 (35h)
instruksi assembly untuk melaksanakan ini sebagai berikut :
mov dl, 5 ; nilai biner
or dalam, 30 ; 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 ; menyalakan CapsLock
pop ds
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 :
11010101 x
XOR 11110000 y
Hasil 00100101 z
XOR 11110000 y
Hasil 11010101 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 ; AL = 11110000b
not al ; 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 ; AL = 10000000b
neg al ; AL = 10000000b, OF = 1
pada kasus lain, untuk bilangan + 127, hasilnya akan benar dan flag overflow
bernilai 0.
mov al, +127 ; AL = 01111111b
neg al ; 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 nilai input
00001001 nilai test
00000001 hasil; ZF = 0
Contoh 2 : bit 0 dan 3 bernilai 0
00100100 nilai input
00001001 nilai test
00000000 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 Hasil Flag
Tujuan < sumber CF = 1
Tujuan = sumber ZF = 1
Tujuan > sumber CF = 0, ZF = 0
Contoh-contoh berikut menunjukan bagaimana flag diset ketika nilai
dibandingkan :
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 Arti
C Carry Flag diset
NC Carry Flag tidak diset (clear)
Z Zero Flag diset
NZ 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 Penjelasan Kondisi Flag
JZ Loncat jika nol ZF = 1
JE Loncat jika sama (jika op1=op2)
JNZ Loncat jika tidak nol ZF = 0
JNE Loncat jika tidak sama (jika
op1<>op2)
JA Loncat jika diatas (jika op1>op2) CF = 0 dan ZF = 0
JNBE Loncat jika tidak lebih rendah atau
sama (jika op1 tidak <= op2)
JAE Loncat jika lebih atas atau sama
(jika op1>= op2)
CF = 0
JNB Loncat jika tidak lebih rendah
(jika op1 tidak < op2 )
JB Loncat jika lebih rendah (jika
op1
CF = 1
JNAE Loncat jika tidak lebih atas atau
sama
(jika op1 tidak >= op2)
JC Loncat jika ada carry
JBE Loncat jika lebih rendah atau sama
(jika op1 <= op2)
CF = 1 atau ZF =1
JNA Loncat jika tidak lebih atas
(jika op1 tidak > op2)
JCXZ Loncat jika CX = 0 CX = 0
JP Loncat jika parity genap PF = 1
JNP Loncat jika tidak ada parity 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 Kondisi Flag
JG Loncat jika lebih besar ZF = 0 dan SF = OF
JNLE Loncat jika tidak lebih kecil atau sama
dengan
JGE Loncat jika lebih besar atau sama dengan SF = OF
JNL Loncat jika tidak lebih kecil
JL Loncat jika lebih kecil SF <> OF
JNGE Loncat jika tidak lebih besar atau sama
dengan
JLE Loncat jika kurang atau sama dengan ZF = 1 atau SF <> OF
JNG Loncat jika tidak lebih besar
JS Loncat jika bertanda SF = 1
JNS Loncat jika tidak bertanda SF = 0
JO Loncat jika overflow OF = 1
JNO Loncat jika tidak overflow OF = 0
Kunci keyboard tambahan.
Rutin berikut menangani kode ASCII dan kunci tambahan :
key db ?
…
…
mov ah, 8
int 21h
cmp al, 0
jne L1
int 21h
L1 : 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
mov small, bl
L1 : 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
. code
main proc
A1 : mov ah,8
Int 21h
cmp al, 0Dh
je A3
cmp al, ‘a’
jb A2
cmp al, ‘z’
ja A2
sub al, 32
A2 : 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 equ 1Ah
cr equ 0Dh
lf equ 0Ah
tab equ 09h
space equ 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
cmp al, ‘A’
jne L1
call proses_A
jmp L4
L1 : cmp al, ‘B’
jne L2
call proses_B
jmp L4
L2 : cmp al, ‘C’
jne L3
call proses_C
jmp L4
L3 : 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 ‘A’
dw proses_A
db ‘B’
dw proses_B
db ‘C’
dw proses_C
db ‘D’
dw 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 :
AL dibandingkan terhadap setiap isi dalam tabel, menggunakan liupan. Yang
pertama sesuai ditemukan dalam tabel menyebabkan pemanggilan offset prosedur
yang disimpan sesudah nilainya :
‘A’ 0120 ‘B’ 0130 ‘C’ 0140 ‘D’ 0150
mov al, input
mov bx, offset casetable
mov cx, 4
L1 : cmp al, [bx]
jne L2
call word ptr [bx +1]
jmp L3
L2 : 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 Shift left
SHR Shift right
SAL Shift arithmetic left
SAR Shift arithmetic right
ROL Rotate left
ROR Rotate right
RCL Rotate carry left
RCR 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.
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 dest, 1
SHL 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
CF
0
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 ; BL = 10001111b
shl bl, 1 ; BL = 00011110b, CF = 1
contoh berikut akan menggeser DX ke kiri sebanyak 3 bit :
mov dx, 000Fh ; DX = 0000000000001111b
mov cl, 4 ; jumlah geser = 3
shl dx, cl ; 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 ; DL = 1
shl dl, 1 ; DL = 2
shl dl, 1 ; DL = 4
shl dl, 1 ; DL = 8
shl dl, 1 ; 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 :
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
CF
0
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 ; DL = 00100000b
shr dl, 1 ; 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 :
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 ; AL = 11110000b (-16)
sar al, 1 ; AL = 11111000b (-8), CF = 0
contoh berikut, -32768 digeser kanan 5 kali, yang sama dengan membaginya
dengan 25 (32). Hasilnya –1024;
mov dx, 8000h ; DX = 1000000000000000b
mov cl, 5
sar dx, cl ; DX = 1111110000000000b
Instruksi ROL (rotate left)
CF
Instruksi ROL memindahkan setiap bit ke kiri. Bit tertinggi dislain ke CF dan ke
bit terendah sebagai berikut :
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 :
Terdapat dua sintak ROR yang sama dengan instruksi ROL :
ROR dest, 1
ROR dest, CL
CF
CF
Contoh berikut menggambarkan, bit terendah disalin ke dalam CF dan ke dalam
bit tertinggi :
mov al, 01h ; AL = 00000001b
ror al, 1 ; AL = 10000000b, CF = 1
ror al, 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 :
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 ; CF = 0
mov bl, 88h ; BL = 10001000b
rcl bl, 1 ; BL = 00010000b, CF = 1
rcl bl, 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 :
Pada contoh berikut, STC menset CF sebelum melaksanakan rotasi :
stc ; CF = 1
mov ah, 10h ; AH = 00010000b, CF = 1
rcr ah, 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.
CF
CF
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 :
byte1 byte2 byte3
Sebelum : 00111011 01000110 11111111
Sesudah : 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
L1 : shr byte1, 1
rcr byte2, 1
rcr byte3, 1
loop L1
byte1 db 3Bh
byte2 db 46h
byte3 db 0FFh
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 DL
0 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 dd 02B2A406h
op2 dd 080108700h
result dw 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 20 40 30 04 36 20 47 A1h
op2 05 52 10 30 4A 26 30 B2h
hasil 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 / Pembagi = Hasil bagi Sisa
AX operand AL AH
DX:AX operand AX BX
Contoh 1. pembagian 8-bit (83h/2=41h, sisa 3) :
mov ax, 0083h ; yang akan dibagi
mov bl, 2 ; pembagi
div bl ; 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 ; AX = FFD0h
mov bl, 5
idiv bl
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 / 10h = 0800h, sisa 1
(DX:AX) (CX) (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 / 10h = 1002h, sisa 0000h
(DX:AX) (CX) (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 ; Bumi = “tanah”
Planet EQU Bumi ; Planet = “tanah” (Salah !)
Planet EQU
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
ABC2 EQU ABC ; ABC2 = “ABC”
ABC EQU
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 INSTR COMMA1+1,ABC3,<,> ; COMMA2 = 8
ABC4 SUBSTR ABC3,5 ; ABC4 = “def,ABC”
ABC5 SUBSTR ABC3,5,3 ; ABC5 = “def”
ABC6 EQU 3+2+1 ; ABC6 = 6
ABC7 EQU %3+2+1 ; ABC7 = “6”
ABC8 EQU %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 ; mulai pendefinisian makro
mov ah, 2
int 21h
endm ; 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 Kode yang diperluas
. code
main proc
…
…
mov dl, ‘A’
. 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
Mengijinkan assembly jika argumen kosong. Nama argumen harus berada
dalam kurung siku.
IFNB Sintak : IFNB
Mengijinkan assembly jika argumen tidak kosong.
IFIDN Sintak : IFIDN
Mengijinkan assembly jika kedua argumen identik. Jika menggunakan
perintah IFIDNI maka perbandingannya case sensitif.
IFDIF Sintak : IFDIF
Mengijinkan assembly jika kedua argumen tidak identik. Jika
menggunakan perintah IFDIFI maka perbandingannya case sensitif.
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
Perintah perintah yang dibangkitkan
1 : call_writeint
2 : push ax
3 : push bx
4 : mov ax, 1000h ; nilai yang akan ditampilkan
5 : mov bx, ; radik yang digunakan (?)
6 : call writeint ; menampilkan AX dalam konsol
7 : pop bx
8 : 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
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 Kode yang diperluas
DOSmsg 1,
DOSmsg 2,
DOSmsg3,
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
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
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 Kode yang dibangkitkan
cmp value1, ax cmp value1, ax
Ccall le, lower 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 ; jika AX <= BX, loncat ke label1
cmpj cx, e, count, exit ; 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 ; 16-bit move
mmove byte2, byte1 ; 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 :
mov cx, 10
L1 : 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,
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,
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 ; jump extended if above or equal
jxz L1 ; jump extended if zero
jxne L4 ; jump extended if not equal
jxg L2 ; jump extended if greater
jxo L1 ; 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,
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 locate
cCall mDisplay
cmpj mMove
display_at mshl
exit mult
getYN putchar
inputInt repeat
inputStr startup
jx_ write
lLoop
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
; 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
; 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
; menginpun integer dan menyimpannya pada
inputInt macro row, col, promt, dest
locate row, col
write prompt
call ReadInt
mov dest, ax
endm
; menampilkan prompt huruf pada
; string ASCIIZ dan menyimpannya ke
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
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
; 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
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.
; 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,
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 Nilai yang dikembalikan
HIGH ekspresi
LENGTH variabel
LOW ekpresi
OFFSET ekpresi
type PTR ekpresi
SEG ekspresi
SHORT label
SIZE variabel
THIS type
. TYPE ekpresi
TYPE ekspresi
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.
Mode dan lingkup 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 ; awal struktur
stnumber db ‘0000000’
lastname db ‘ ‘ ; 20 spasi
credits dw 0
status dw 0
StudentStruc ends ; 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 StudentStruc <’12345567’, ‘Dedi’, 30, 1> ; seluruh field
myRecord StudentStruc <,,50,0> ; 2 field terakhir
yourRecord StudentStruc <,’Dodi’> ; 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 :
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
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 :
0 0 0 1 0 0 1 0 0 1 1 0 1 0 1 0
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 :
0 0 0 1 0 0 1 0 0 1 1 0 1 0 1 0
tahun = 9 bulan=3 hari=10
Field Nilai geser
Year 9
Month 5
Day 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 ;u/ clear screen
push ax
push bx
push cx
push dx
mov ah,06h ;siapin service & attr layar
mov cx,0000h
mov al,00h
mov bh,07H
mov dh,24h
mov dl,79h
int 10h ;pake interupt 10h
pop dx
pop cx
pop bx
pop ax
ENDM
GoToXY MACRO col,row ;u/ goto cursor
push ax
push bx
push dx
mov dh,row ;simpan baris di dh
mov dl,col ;simpan kolom di dl
mov ah,02h
mov bh,00 ;warna biasa
int 10h ;pake int 10h
pop dx
pop bx
pop ax
ENDM
PrintIt MACRO buffer ;u/ cetak kelayar
push ax
push dx
lea dx,buffer
mov ah,09h ;pakai servis 09h u/ print string
int 21h ;pake int 21h
pop dx
pop ax
ENDM
OpenFile MACRO ;u/ open file
mov al,02h
mov ah,3dh ;buka file dengan nama filename
lea dx,FileName
int 21h
mov FileHand,ax ;simpan penanganannya ke variabel
ENDM ;filehand
ReadFile MACRO ;u/ untuk read file
mov ah,3fh
mov bx,FileHand ;dari variabel filehand
mov cx,81 ;sebanyak 81 karakter
lea dx,InfoData ;simpan isi file pada variabel
int 21h ;infodata
ENDM
CloseFile MACRO ;u/ close file
mov ah,3eh
mov bx,FileHand ;var filehand ditutup
int 21h
ENDM
SendFile MACRO ;u/ write to file
mov ah,40h
mov bx,FileHand ;ke variabel filehand
mov ch,0
mov cl,InfoLine ;sebanyak cx=banyak karakter
lea dx,InfoData ;karakter yg disimpan diambil dr
int 21h ;variabel infodata
ENDM
FileIndex MACRO ;u/ file pointer
mov al,02h ;tidak jadi diimplementaikan
mov ah,42h ;karena program tidak dapat melakukan
mov bx,FileHand ;reedit.
mov cx,0h ;fungsi:u/ nunjuk ke EOF
mov dx,0h
int 21h
ENDM
CreateFile MACRO ;u/ bikin file
mov ah,3ch
mov cx,00 ;dengan type file biasa
lea dx,FileName ;dengan nama filename
int 21h
ENDM
Clearence MACRO ;u/ ngapus editor
push cx
mov ch,00
mov cl,02
RepeatClearence:
GotoXY 00,cl
PrintIt BlankLine ;kosongkan baris
inc cx ;dari baris 2 sampai baris 22
cmp cx,22 ;dari cl=2 sampa cl=22
jne RepeatClearence
pop cx
ENDM
.DATA
MainMenu DB 'X:Exit S:Save O:Open$'
BlankLine DB ' $'
GiveLine DB
'===============================================$'
Interface DB 'Tekan ESC untuk Menu$ '
MsgFileSaved DB 'File Disimpan!$'
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 ;Awal Program
mov ax,DGROUP ;tunjuk segmen data
mov ds,ax
mov es,ax
CLRSCR ;format layar
GoTOXY 00,01
PrintIT GiveLine ;baris 1 pake garis
GotoXY 00,22
PrintIt GIveLine ;baris 22 pake garis
GotoXY 00,23
PrintIt Interface ;tulis help u/ menu
GotoXY 00,02
lea dx,InfoStruct ;tunjuk alamat mem u/ file
mov InfoLine,00 ;set isi buffer mem 0
input: ;input caracter
mov ah,07 ;wait 4 input
int 21h
cmp al,1Bh ;esc char check
je OpenMenu
cmp al,0dh ;enter check
je AddLine
cmp al,08h ;Backspace Chek
je ToBackSPACE
cmp al,20h ;cek apakah input karakter yg legal
jnl disp ;antara 20h s/d 7eh
cmp al,7Eh
jng disp ;klo ya, tampilin ke layar
jmp input ;klo enggak, minta input lagi
disp:
mov dl,al ;display char
mov ah,02
int 21h
inc Column ;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: ;bantuan u/ ke jmp ke BACKSPACE
jmp 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 ;bersihin baris 23
PrintIt BlankLine
GotoXY 0,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 ;kosongkan baris 24
PrintIt BlankLine
GotoXY 00,24
PrintIt MsgFileOpen ;tampilin pesen minta file
lea dx,FileStruct ;load struktur file
mov ah,0ah ;minta nama file dari keybd
int 21h
mov bh,0
mov bl,actlen
mov fileName[bx],' ' ;ilangin enter pada namafile
CreateFile ;bikin filenya
OpenFile ;buka filenya
; FileIndex ;ini u/ reedit file.
;tidak jadi diimpelementasikan
;karena ketertbatasan interface
lea dx,InfoStruct ;load struktur file
SendFile ;simpan ke file
GotoXY 00,24
PrintIt BlankLine ;tampilin pesen bahwa file
GotoXY 00,24 ;berhasil disimpan
PrintIt MsgFileSaved
jmp Revert
OpenMe: ;rutin pembacaan file
GotoXY 00,24
PrintIt BlankLine ;kosongkan baris pesan
GotoXY 00,24
PrintIt MsgFileOpen ;pesan minta file
lea dx,FileStruct ;load struktur file
mov ah,0ah ;minta file dari input keybd
int 21h
mov bh,0
mov bl,actlen
mov Filename[bx],'$' ;beri tanda endstr pada nama file
GotoXY 00,00
PrintIt BlankLine
GotoXY 00,04
PrintIt BlankLine
GotoXY 00,00
PrintIt FileName ;tampilin nama file di baris plg atas
mov Filename[bx],' ' ;kosongkan endstr nama file
Clearence ;bersihin editor
OpenFile ;buka file
cld ;hapus isi buffer infodata saat ini
lea di,infodata ;biar enggak ngganggu tampilan
mov cx,40 ;sebanyak 40x2 karakter
mov ax,2020h ;isi dengan karakter spasi
rep stosw ;repeat untuk all byte infodata
lea dx,InfoStruct ;load struktur isi file
ReadFile ;baca filenya
GotoXY 00,02 ;pindahin kursor
PrintIt InfoData ;tulis isi filenya
CloseFile ;tutup file
jmp Revert ;kembali ke mode edit
Revert:
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 ;bersihin layar
GotoXY 00,00
mov ah,4ch ;keluar dari program
int 21h
BackSpace:
cmp Column,00 ;klo udah diawal baris
je ToInput ;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 Type instruksi RET
Prosedur assembler yang dibangkitkan oleh assembler
subroutine_1 proc near RET (near)
subroutine_2 proc far 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 Stack
push row
push col
call Locate
Ketika LOCATE mengendalikan, SP menunjuk alamat kembali (return address).
Kita memasukan salinan BP ke dalam stack untuk menjaga nilainya, kemudian
menset BP ke SP :
10
20
ret addr
Instruksi Stack
push bp
mov bp, 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
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.
10
20
ret addr
BP
10
20
ret addr
BP
xx
xx
row_val
col_val
[BP+6]
[BP+4]
[BP+2]
BP
[BP-2]
[BP-4]
SP
SP
Instruksi Stack
mov sp, bp
pop bp
ret 4
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 :
Dalam subrutin kita harus menghapus byte atas setiap paramter karena nilainya
tidak didefinisikan.
and [bp+4], 0FFh
and [bp+6], 0FFh
10
20
ret addr
SP
ch
flag
ret addr
BP BP =SP
[BP+6]
[BP+4]
[BP+2]
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 :
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
segment
offset
ret addr
BP
[BP+6]
[BP+4]
[BP+2]
BP =SP
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 Pascal untuk COUNT_CHAR menyertakan peringah
EXTERNAL :
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 mengambil mode video}
$CD/$10/ {int 10h}
$B4/$00/ {mov ah, 0 menset mode video }
$CD/$10) {int 10h}
$B4,$02/ {mov ah, 2 posisi kursor }
$BA/$00 {mov dx, 0 pada baris , kolom}
$B7/$00 {mov bh, 0 pada halaman video 0}
$CD/$10 {int 10h}
End;
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 : NEAR
EXTRN FarProc : FAR
AsmProc PROC NEAR
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.
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 ; procedure MyProc(i,j : integer);
PUBLIC MyProc
J EQU WORD PTR [bp+6] ; j diatas bp & alamat kembali
I EQU WORD PTR [bp+8] ; I diatas j
Push bp ; mempersiapkan BP pemanggil
Mov bp,sp ; BP menunjuk pada puncak stack
Mov ax,I ; 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
. MODEL large, PASCAL
. CODE
MyProc 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 SEGMENT
ASSUME cs : CODE
MyProc PROC FAR
PUBLIC MyProc
J EQU WORD PTR ss:[bx+4]
I 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 SEGMENT PUBLIC
MyInt DW?
MyByte DB?
…
DATA 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
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
HexStr ENDP
CODE 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
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 :
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 Instruksi
018E push [0352]
0192 push [034C]
0196 push [0350]
019A call 01B1
019D add SP, +06
01A0 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
0003
0002
0001
ret addr
BP
[BP + 8]
[BP + 6]
[BP + 4]
[BP + 2]
BP -->
c
b
a
SP
sampai akhir file input dicapai. Subrutin assembly mengenkripsi semua karakter
dalam buffer dengan operasi XOR karakter dengan suatu nilai. Berikut
#include
#include
#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
File Sumber Assembler :
FILENAME.ASM
Borland C++ Turbo assembler
File Objek
FILENAME.OBJ
File Objek
FILENAME.OBJ
TLINK
File yang dapat
dieksekusi
FILENAME.EXE
COMPILE 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 proc near
push bp
mov bp, sp
pop bp
ret
@test$qv 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 small
. DATA
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
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 WORD PTR [bp+8]
push ax
call _IntDivide
add sp, 4
pop bp
ret
_Average ENDP
END
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
sumber:http://www.ittelkom.ac.id/library/e-book/261206020104.pdf
