Minggu 6 Pemrograman

Bab 6: Kode Mesin & Instruksi Data Movement

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.

6.1 Apa Itu Kode Mesin?

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.
Prefix (Opsional)

Mengubah perilaku instruksi. Contoh: REP (ulangi string ops), SEG: (override segmen), LOCK (bus lock).

Opcode (Wajib)

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:

Register 8-bitOpcode Register 16-bitOpcode
ALB0AXB8
CLB1CXB9
DLB2DXBA
BLB3BXBB
AHB4SPBC
CHB5BPBD
DHB6SIBE
BHB7DIBF
Assembly + Machine Code
; === Immediate ke Register === B8 34 12 MOV AX, 1234H ; 3 byte: opcode + imm16 (little-endian) B1 05 MOV CL, 5 ; 2 byte: opcode + imm8 ; === Register ke Register === 89 C3 MOV BX, AX ; 2 byte: opcode + ModR/M 8B D8 MOV BX, AX ; 2 byte (alternatif, opcode 8B) ; === Register ke Memori (Direct) === 89 0E 00 20 MOV [2000H], CX ; 4 byte: opcode + ModR/M + addr16 ; === Memori ke Register (Indirect) === 8B 14 MOV DX, [SI] ; 2 byte: opcode + ModR/M (r/m=100=[SI]) ; === Segment Register (Harus lewat Register Umum) === 8E D8 MOV DS, AX ; 2 byte: opcode 8E + ModR/M

📑 Catatan Penting: Little-Endian pada Immediate

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 AX50150H + kode reg (AX=000)
PUSH BX53150H + kode reg (BX=011)
PUSH CX51150H + kode reg (CX=001)
POP AX58158H + kode reg (AX=000)
POP BX5B158H + 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: PUSH AX (Asumsi AX = 1234H, SP = 1000H)

1. KEADAAN AWAL
SP: 1000H
AX: 1234H
SP = SP - 2
SP = 0FFEH
2. SETELAH EKSEKUSI
SP: 0FFEH
AX: 1234H
Isi Memori (Little-Endian):
0FFEH: 34H (AL)
0FFFH: 12H (AH)

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.

InstruksiKode MesinByteCatatan
XCHG AX, BX93190H + reg (BX=3). Catatan: XCHG AX,AX = 90H = NOP!
XCHG AX, CX91190H + reg (CX=1)
XCHG BX, CX87 CB2Opcode 87H + ModR/M (11_001_011)
Sebelum XCHG AX, BX
AX1000H
BX2000H
Setelah XCHG AX, BX
AX2000H
BX1000H

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).

C5 14 LDS SI, [SI] ; SI = [SI], DS = [SI+2] ; Memori: [SI] = 0050H, [SI+2] = 2000H

LAHF & SAHF

Menyalin byte rendah register Flag ke AH atau sebaliknya. Encoding 1 byte masing-masing.

9F LAHF ; AH = Flag byte rendah 9E SAHF ; 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 xxxx LEA BX, [TABEL_7SEG] ; BX = alamat awal tabel B0 05 MOV AL, 05H ; AL = indeks 5 D7 XLAT ; 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...

2. Pada byte ModR/M, nilai field mod = 11 (biner) berarti...

3. Manakah instruksi di bawah ini yang VALID menurut aturan assembler 8086?

4. Apa yang terjadi terhadap register SP saat instruksi PUSH BX dieksekusi?

5. Instruksi XLAT digunakan untuk keperluan apa?

6. Instruksi LEA SI, [BX+DI+10H] akan menghasilkan apa di dalam register SI?

7. Berapa total byte kode mesin yang dihasilkan oleh instruksi PUSH AX?