Memahami bagaimana instruksi Assembly diterjemahkan menjadi kode mesin (machine code) yang dieksekusi prosesor, serta menguasai instruksi perpindahan data pada 8086.
Capaian Pembelajaran Bab Ini
Mahasiswa mampu menjelaskan hubungan antara bahasa Assembly dan kode mesin, memahami format encoding instruksi 8086 (opcode, ModR/M, displacement, immediate), menuliskan kode mesin dari instruksi perpindahan data yang sederhana, serta menguasai instruksi MOV, PUSH, POP, XCHG, dan LEA.
Prosesor tidak memahami teks seperti MOV AX, 1234H. Satu-satunya bahasa yang dipahami CPU adalah kode mesin (machine code) — yaitu deretan bilangan biner yang merepresentasikan instruksi. Bahasa Assembly hanyalah representasi manusia-bisa-baca dari kode mesin tersebut.
Proses Dari Assembly Hingga Eksekusi oleh CPU
Bahasa Assembly
MOV AX, 1234H
Assembler
Kode Mesin (Hex)
B8 34 12
Biner
Kode Mesin (Bin)
10111000 00110100 00010010
Dieksekusi oleh
Unit Eksekusi 8086 (EU)
Bahasa Assembly (Mnemonik)
✓ Dibaca manusia — menggunakan kata singkat (mnemonik)
✓ Bisa menggunakan label (misal: JMP LOOP)
✓ Memiliki komentar untuk dokumentasi
✓ Ukuran file sumber bisa besar, tapi mudah dipelihara
Kode Mesin (Binary/Hex)
✓ Hanya berisi angka — langsung dipahami CPU
✓ Tidak ada label — hanya alamat numerik
✓ Tidak ada komentar
✓ Sangat ringkas — setiap byte memiliki makna spesifik
💡 Mengapa Perlu Memahami Kode Mesin?
▸Debugging tingkat rendah — saat menggunakan debugger (seperti Debug.exe atau TD), Anda akan melihat kode mesin, bukan Assembly.
▸Memahami ukuran program — mengetahui berapa byte yang dihasilkan tiap instruksi membantu optimasi memori.
▸Memahami arsitektur CPU — melihat bagaimana opcode, ModR/M, dan operand di-encode mengungkap cara kerja internal prosesor.
▸Hubungan 1-ke-1 — setiap instruksi Assembly umumnya memiliki tepat satu representasi kode mesin (relasi bijektif).
6.2 Format Instruksi 8086
Setiap instruksi 8086 disusun dari beberapa field (bagian) yang disusun secara berurutan di memori. Tidak semua field selalu hadir — tergantung jenis instruksi. Berikut adalah format umumnya:
Format Umum Instruksi 8086
Prefix
0–4 byte
Opcode
1–2 byte
ModR/M
0–1 byte
Displacement
0–2 byte
Immediate
0–2 byte
* Field SIB (Scale-Index-Base) tidak ada pada 8086 — baru diperkenalkan pada prosesor 80386.
Menentukan operasi apa yang dilakukan (MOV, ADD, SUB, dst.). Biasanya 1 byte, beberapa instruksi memerlukan 2 byte. Juga mengandung bit w (word/bit: 0=8-bit, 1=16-bit) dan bit d (direction: 0=reg adalah tujuan, 1=reg adalah sumber).
ModR/M (Kondisional)
Menentukan mode pengalamatan dan register mana yang terlibat. Hadir pada hampir semua instruksi yang melibatkan register atau memori. Detail di bawah.
Displacement (Kondisional)
Offset alamat memori tambahan. Bisa 0 byte (tidak ada), 1 byte (8-bit, sign-extended), atau 2 byte (16-bit).
Immediate (Kondisional)
Nilai konstan (literal) yang disertakan dalam instruksi. Bisa 1 byte (8-bit) atau 2 byte (16-bit, Little-Endian).
Detail Byte ModR/M
Byte ModR/M adalah 1 byte yang dibagi menjadi 3 field, dan menjadi "kunci" untuk memahami encoding instruksi 8086:
mod
2 bit
reg/opcode
3 bit
r/m
3 bit
Field mod (2 bit)
Menentukan mode pengalamatan:
00 — Memori, tanpa displacement
01 — Memori, displacement 8-bit
10 — Memori, displacement 16-bit
11 — Register (bukan memori)
Field reg (3 bit)
Menentukan register operand (tergantung bit w di opcode):
000=AL/AX 001=CL/CX
010=DL/DX 011=BL/BX
100=AH/SP 101=CH/BP
110=DH/SI 111=BH/DI
Field r/m (3 bit)
Menentukan operand kedua (register atau mode memori):
000=[BX+SI] 001=[BX+DI]
010=[BP+SI] 011=[BP+DI]
100=[SI] 101=[DI]
110=Direct* 111=[BX]
*Jika mod=00, r/m=110 berarti direct address 16-bit.
Contoh Dekonstruksi: MOV AX, [BX+SI+5]
Kode mesin: 8B 40 05
Byte 1
8B
= 10001011₂
Opcode= 100010 (MOV r16, r/m16)
d=1→ reg = sumber
w=1→ 16-bit
Byte 2
40
= 01000000₂
mod=01→ disp 8-bit
reg=000→ AX
r/m=000→ [BX+SI]+disp
Byte 3
05
= 00000101₂
disp8= +5
Offset tambahan di-sign-extend ke 16-bit
Arti: MOV AX, [BX+SI+5] — Baca 16-bit data dari alamat memori BX+SI+5, simpan ke AX. Total: 3 byte.
6.3 Instruksi MOV dan Kode Mesinnya
MOV adalah instruksi perpindahan data yang paling dasar. Fungsinya menyalin data dari source ke destination. Ukuran data harus sama (8-bit ke 8-bit, atau 16-bit ke 16-bit). Berikut berbagai bentuk MOV beserta kode mesinnya:
Instruksi Assembly
Opcode
Kode Mesin
Byte
Keterangan
MOV AX, 1234H
B8
B8 34 12
3
Immediate ke reg 16-bit
MOV CL, 5
B1
B1 05
2
Immediate ke reg 8-bit
MOV BX, AX
89
89 C3
2
Reg ke reg (ModR/M: 11_000_011)
MOV AX, [SI]
8B
8B 04
2
Memori [SI] ke reg (r/m=100)
MOV [2000H], CX
89
89 0E 00 20
4
Reg ke memori direct (mod=00, r/m=110)
MOV DS, AX
8E
8E D8
2
Reg ke segmen (ModR/M: 11_011_000)
💡 Pola Encoding MOV Register-Immediate
Instruksi MOV reg, immediate memiliki encoding khusus yang sangat ringkas — tidak memerlukan byte ModR/M. Opcode-nya langsung mengandung informasi register tujuan:
Perhatikan contoh MOV AX, 1234H → kode mesin B8 34 12. Nilai 1234H ditulis sebagai 34 12 (bukan 12 34). Ini karena 8086 menyimpan multi-byte data dalam format Little-Endian: byte paling rendah (low byte = 34H) disimpan di alamat memori paling rendah. Aturan ini berlaku untuk semua nilai immediate dan displacement 16-bit.
6.4 Operasi Stack: PUSH & POP
Stack adalah area memori khusus yang bekerja dengan prinsip LIFO (Last In, First Out). Instruksi PUSH menyimpan data 16-bit ke stack, dan POP mengambilnya kembali.
Instruksi
Kode Mesin
Byte
Catatan
PUSH AX
50
1
50H + kode reg (AX=000)
PUSH BX
53
1
50H + kode reg (BX=011)
PUSH CX
51
1
50H + kode reg (CX=001)
POP AX
58
1
58H + kode reg (AX=000)
POP BX
5B
1
58H + kode reg (BX=011)
Encoding sangat efisien: PUSH dan POP register hanya memerlukan 1 byte saja. Ini karena opcode-nya (50H–57H untuk PUSH, 58H–5FH untuk POP) langsung meng-encode register tujuan dalam 3 bit terakhir opcode — tidak perlu byte ModR/M tambahan.
Mekanisme Diagram: POP BX (Melanjutkan kondisi di atas)
1. KEADAAN AWAL
SP:0FFEH
BX:????H
Baca Memori di SP
SP = SP + 2 SP = 1000H
2. SETELAH EKSEKUSI
SP:1000H
BX:1234H
6.5 Aturan Penting Gerakan Data
Tidak semua kombinasi sumber dan tujuan diizinkan oleh arsitektur 8086. Melanggar aturan ini akan menyebabkan error saat assembling — dan pada level kode mesin, instruksi seperti itu sama sekali tidak memiliki encoding yang valid.
✗ DILARANG (Illegal — Tidak Ada Encoding)
MOV [BX], [SI]
→ Memori ke Memori (Tidak ada jalur langsung di bus)
MOV DS, ES
→ Segmen ke Segmen (Hardware tidak mendukung)
MOV CS, AX
→ Memodifikasi CS langsung (Mengacaukan pipeline)
MOV 1234H, AX
→ Immediate ke Memori (Tujuan tidak boleh konstan)
✓ SOLUSI ALTERNATIF (Legal)
MOV AX, [SI] ; MOV [BX], AX
→ Gunakan register sebagai perantara
MOV AX, ES ; MOV DS, AX
→ Gunakan register umum untuk salin segmen
JMP FAR LABEL
→ Untuk mengubah CS, gunakan lompatan jauh
MOV AX, 1234H ; MOV [BX], AX
→ Muat ke register dulu, baru ke memori
Perspektif Kode Mesin: Aturan-aturan "ilegal" ini bukan sekadar ketentuan assembler — ini adalah keterbatasan hardware. Encoding instruksi 8086 dirancang sedemikian rupa sehingga bit-bit yang tersedia dalam opcode dan ModR/M secara fisik tidak mampu merepresentasikan operasi seperti memori-ke-memori dalam satu instruksi. Assembler hanya menerjemahkan aturan hardware ini ke pesan error yang bisa dipahami programmer.
6.6 Instruksi XCHG (Exchange)
XCHG menukar isi dua operand sekaligus. Memiliki encoding khusus yang sangat ringkas jika salah satu operand-nya adalah AX.
Perhatian: Sama seperti MOV, XCHG tidak bisa dilakukan langsung dari memori ke memori (misal: XCHG [BX], [SI] adalah ilegal).
6.7 Instruksi LEA (Load Effective Address)
LEA menghitung alamat offset (EA) dari sebuah operan memori, lalu menyimpan angka alamatnya ke register tujuan, BUKAN mengambil data di dalam memori tersebut. Opcode-ya adalah 8D.
Perbandingan: LEA vs MOV
Asumsi: BX = 1000H, SI = 2000H. Isi data di alamat fisik 13005H adalah FFH.
LEA AX, [BX+SI+5]
→ 8D 40 05
Proses: Hitung EA saja. Tidak ke RAM.
EA = 1000H + 2000H + 5 = 3005H
Hasil di AX:3005H
MOV AX, [BX+SI+5]
→ 8B 40 05
Proses: Hitung EA, lalu BACA RAM di alamat tersebut.
EA = 3005H → Fisik = (DS×16)+3005H
Hasil di AX:00FFH(Data di RAM)
Perhatikan kesamaan encoding: LEA AX, [BX+SI+5] = 8D 40 05 dan MOV AX, [BX+SI+5] = 8B 40 05. Satu-satunya perbedaan adalah byte pertama (opcode: 8D vs 8B). Byte ModR/M dan displacement-nya identik, karena keduanya menggunakan kalkulasi alamat yang sama — bedanya hanya pada apa yang dilakukan dengan hasil kalkulasi tersebut.
6.8 Instruksi Khusus Lainnya
LDS & LES
Load pointer menggunakan DS atau ES. Mengambil 4 byte dari memori sekaligus. Opcode: C5 (LDS) dan C6 (LES).
Menyalin byte rendah register Flag ke AH atau sebaliknya. Encoding 1 byte masing-masing.
9FLAHF; AH = Flag byte rendah9ESAHF; Flag byte rendah = AH
XLAT (Translate Table)
Membaca 1 byte dari tabel di memori yang ditunjuk BX + AL, lalu menyimpannya kembali ke AL. Opcode: D7 — hanya 1 byte, tidak ada operand eksplisit.
8D 1E xxxxLEA BX, [TABEL_7SEG] ; BX = alamat awal tabelB0 05MOV AL, 05H; AL = indeks 5D7XLAT; AL = isi memori di [BX + AL]
6.9 Soal Latihan & Kuis
Soal 1. Instruksi Assembly MOV AX, 1234H ditulis dalam kode mesin sebagai B8 34 12. Jelaskan mengapa nilai 1234H ditulis terbalik menjadi 34 12 di memori.
▶ Lihat jawaban
Karena arsitektur 8086 menggunakan penyimpanan Little-Endian: byte rendah (low byte) disimpan di alamat memori yang lebih rendah, dan byte tinggi (high byte) di alamat yang lebih tinggi. Nilai 1234H terdiri dari byte rendah 34H dan byte tinggi 12H, sehingga di memori urutannya menjadi 34H lalu 12H.
Soal 2. Mengapa instruksi MOV DS, ES menyebabkan error pada assembler 8086? Bagaimana cara yang benar untuk menyalin nilai ES ke DS?
▶ Lihat jawaban
Karena arsitektur 8086 melarang operasi langsung antar register segmen (kecuali ke CS melalui instruksi khusus seperti JMP FAR). Cara yang benar adalah menggunakan register umum sebagai perantara: MOV AX, ES; MOV DS, AX.
Soal 3. Jelaskan perbedaan mendasar antara instruksi LEA BX, [SI+5] dengan MOV BX, [SI+5].
▶ Lihat jawaban
LEA menghitung alamat offset-nya saja (SI + 5) dan menyimpan hasil penjumlahan tersebut ke BX. MOV menghitung alamat yang sama, lalu pergi ke memori (RAM) pada alamat tersebut untuk mengambil data, baru menyimpan data tersebut ke BX. LEA tidak mengakses memori sama sekali, sehingga lebih cepat untuk kalkulasi matematika alamat.
Soal 4. Jika awalnya SP = 1000H dan AX = 1234H, berapa nilai SP setelah instruksi PUSH AX dieksekusi? Tuliskan isi memori di alamat baru SP.
▶ Lihat jawaban
PUSH mengurangi SP terlebih dahulu. SP baru = 1000H - 2 = 0FFEH. Karena 8086 bersifat Little-Endian, byte rendah (34H) disimpan di alamat 0FFEH, dan byte tinggi (12H) di alamat 0FFFH.
Kuis Bab 6
1. Instruksi Assembly MOV AX, 1234H jika dikonversi ke kode mesin (hex) menjadi...
Opcode untuk MOV AX, imm16 adalah B8H, diikuti immediate 1234H dalam format Little-Endian: byte rendah (34H) dulu, lalu byte tinggi (12H). Jadi hasilnya B8 34 12.
2. Pada byte ModR/M, nilai field mod = 11 (biner) berarti...
mod=11 berarti operasi register-ke-register. Tidak ada pengalamatan memori yang terlibat, sehingga tidak ada displacement byte setelah ModR/M.
3. Manakah instruksi di bawah ini yang VALID menurut aturan assembler 8086?
8086 tidak mengizinkan operasi memory-to-memory (opsi 1 salah), segment-to-segment langsung (opsi 2 salah), dan nilai immediate tidak bisa menjadi destination (opsi 4 salah). Opsi 3 (Based Indexed) adalah sintaks yang valid.
4. Apa yang terjadi terhadap register SP saat instruksi PUSH BX dieksekusi?
Stack pada 8086 tumbuh ke arah alamat memori yang lebih rendah (downward-growing). Oleh karena itu, sebelum menyimpan data, SP dikurangi 2 (SP = SP - 2), lalu data ditulis di alamat SP yang baru.
5. Instruksi XLAT digunakan untuk keperluan apa?
XLAT mengambil 1 byte dari alamat memori BX + AL, lalu menyimpannya kembali ke AL. Sangat berguna untuk konversi cepat (misalnya kode ASCII ke kode 7-segmen) menggunakan tabel 256 elemen.
6. Instruksi LEA SI, [BX+DI+10H] akan menghasilkan apa di dalam register SI?
LEA (Load Effective Address) menghitung offset tujuan (BX+DI+10H) dan menyimpan hasil penjumlahan angka tersebut ke SI, tanpa perlu mengakses memori RAM untuk membaca data.
7. Berapa total byte kode mesin yang dihasilkan oleh instruksi PUSH AX?
PUSH register 16-bit memiliki encoding khusus 1 byte: 50H+kode register. Karena AX memiliki kode 000, maka PUSH AX = 50H. Cukup 1 byte — tidak perlu ModR/M karena register yang bisa di-PUSH sudah di-encode dalam opcode-nya.