ALU adalah singkatan dari arithmetic logic unit, atau unit aritmetika logika, yaitu blok kombinasional yang menghitung operasi aritmetika dan logika bagi prosesor. Topik ini merancang ALU kecil beserta mekanisme pemilihan operasinya, mendefinisikan status flag Zero, N, C, dan V yang diterbitkannya, lalu menghubungkan flag tersebut dengan keputusan percabangan. Flag adalah keluaran satu bit yang melaporkan sifat hasil, dan keduanya terbit bersamaan pada setiap operasi. Implementasinya ditulis dalam Python dengan operan berupa deretan bit, sehingga jalur data dan jalur status terlihat terpisah dengan jelas.
ALU sebagai blok kombinasional#
ALU menerima dua operand dan satu kelompok bit kontrol, lalu menerbitkan hasil beserta sekumpulan flag tanpa memerlukan elemen penyimpan. Sifat kombinasional ini berarti keluarannya murni fungsi dari masukan pada saat itu juga. Pembagian kerjanya tetap, yaitu bagian perhitungan berada di dalam dan bagian pemilihan berada di depannya. Bit kontrol tidak ikut dihitung, tetapi menentukan jalur mana yang hasilnya diteruskan keluar.
Diagram berikut menunjukkan antarmuka ALU secara umum, yaitu dua masukan operand, satu masukan bit kontrol, satu keluaran hasil, dan satu keluaran flag. Lebar operand menentukan harga fisiknya, karena setiap operasi harus tersedia untuk setiap jalur bit. ALU 32 bit berisi 32 salinan rangkaian satu bit yang bekerja paralel, dengan carry yang menyambung di antara salinan-salinan itu pada operasi penjumlahan.
Operasi yang disediakan ALU#
Sekumpulan operasi minimum ALU serbaguna terdiri atas AND, OR, add, sub, dan slt. AND dan OR bekerja per bit tanpa memedulikan tanda. Add menjumlahkan dua bilangan komplemen dua dengan penjumlah biner biasa. Sub mengurangkan dengan menjumlahkan operand pertama dan negasi operand kedua, yaitu balik semua bit lalu tambah satu. Slt, singkatan dari set less than, menghasilkan 1 apabila operand pertama lebih kecil daripada operand kedua dalam pembacaan bertanda, dan 0 apabila sebaliknya.
| Operasi | Pembacaan operand | Hasil |
|---|---|---|
| and | bit per bit | AND dari kedua operand |
| or | bit per bit | OR dari kedua operand |
| add | komplemen dua | jumlah kedua operand |
| sub | komplemen dua | selisih melalui penjumlahan negasi |
| slt | komplemen dua | 1 bila operand pertama lebih kecil, selain itu 0 |
Daftar ini memang pendek, tetapi operasi yang lebih kompleks dapat disusun darinya. Perkalian, pembagian, dan geser bit biasanya berada di luar ALU inti pada desain sederhana, lalu diangkat menjadi unit terpisah atau instruksi tersendiri pada desain yang lebih lengkap. Pilihan operasi minimum di atas sudah cukup untuk penghitungan alamat, logika biner, dan seluruh perbandingan yang dibutuhkan percabangan.
Pemilihan operasi dengan bit kontrol#
Bit kontrol adalah kode yang menyertai instruksi, dan tugas ALU adalah menerjemahkannya menjadi pemilihan jalur. Cara paling langsung adalah mengerjakan semua operasi secara paralel lalu memilih satu keluarannya dengan multiplexer, rangkaian pemilih satu dari banyak masukan. Pendekatan ini boros gerbang, tetapi menggambarkan prinsipnya dengan jelas. Desain yang hemat berbagi rangkaian, misalnya sub memakai jalur add dengan operand kedua yang dinegasikan, dan slt memakai jalur sub dengan keluaran yang dipilih ulang.
Lebar bit kontrol mengikuti banyaknya operasi yang harus dipilih. Lima operasi cukup dilayani tiga bit kontrol karena kombinasi masih menyisakan kode kosong untuk operasi tambahan di kemudian hari. Pada demo di bagian akhir, pemilihan dijalankan sebagai percabangan Python demi keterbacaan, sedangkan padanan perangkat kerasnya adalah gerbang seleksi yang meneruskan hasil satu operasi dan menahan sisanya.
Potongan berikut memperlihatkan bagian yang menghitung flag setelah hasil dan carry tersedia. Kamus flag itulah yang dikembalikan bersama hasil oleh demo pada bagian akhir topik.
# tidak-dijalankan
flag = {
"Zero": int(all(bit == 0 for bit in hasil)),
"N": hasil[-1], # bit tanda hasil
"C": c, # carry keluar atau pinjaman
"V": carry_tanda ^ raw_carry, # carry masuk XOR carry keluar bit tanda
}Status flag dan kegunaannya#
Setiap operasi ALU menerbitkan flag bersamaan dengan hasilnya. Zero menyala apabila semua bit hasil bernilai 0. N (negative) menyalin bit tanda hasil. C menyimpan carry keluar untuk penjumlahan atau pinjaman untuk pengurangan. V melaporkan overflow aritmetika bertanda melalui rumus yang sama seperti pada representasi komplemen dua.
Masing-masing flag punya pemakai utamanya. Flag Zero adalah dasar pengujian kesamaan, karena membandingkan dua nilai berarti mengurangkannya lalu menguji apakah hasilnya nol. Flag N membedakan hasil positif dan negatif, dan menjadi dasar perbandingan lebih kecil atau lebih besar ketika overflow tidak terjadi. Flag C dipakai aritmetika presisi ganda untuk merangkai penjumlahan 64 bit dari beberapa penjumlahan 32 bit. Flag V menjadi dasar deteksi hasil yang tidak sah pada aritmetika bertanda.
Percabangan menyandarkan diri pada flag, bukan pada nilai operand secara langsung. Prosesor mengeksekusi lompatan bersyarat dengan menguji flag yang ditinggalkan operasi sebelumnya, misalnya melompat bila Zero menyala. Pola hitung terlebih dahulu lalu uji itulah yang membuat flag wajib terbit pada setiap operasi ALU, meskipun tidak semua instruksi berikutnya memakai nilai tersebut.
Slt dan perbandingan bertanda#
Instruksi slt pada RISC-V menyimpan 1 ke register tujuan apabila operand pertama lebih kecil daripada operand kedua dalam pembacaan bertanda, dan menyimpan 0 apabila sebaliknya. ALU menghitungnya tanpa pembanding terpisah dengan memanfaatkan pengurangan. Hitung a - b, lalu periksa sifat hasilnya. Apabila hasilnya negatif tanpa overflow, maka a < b. Kondisi itu persis N XOR V pada hasil sub, dan itulah rumus yang dipakai demo di bagian akhir.
Perbandingan kesamaan melengkapi slt dan kembali bersandar pada flag Zero. Menguji a = b berarti menguji apakah hasil a - b membuat Zero menyala, sedangkan a < b dijawab kombinasi N dan V. Dengan dua jawaban ini, seluruh perbandingan bertanda dibangun dari adder dan pemilih jalur, tanpa rangkaian pembanding khusus.
Sebagai instruksi aritmetika biasa, hasil slt masuk register, dapat dihitung ulang, disimpan, lalu diuji kemudian, sehingga perbandingan menjadi nilai biasa bagi mesin. Tanpa mengajarkan assembly, cukup dicatat bahwa mekanisme perbandingannya tetap bersandar pada selisih dua operand yang dihitung ALU.
Demo ALU lengkap#
Implementasi berikut menyatukan semuanya. Fungsi alu menerima dua operand 8 bit dan nama operasi, lalu mengembalikan hasil beserta kamus flag. Operasi and dan or bekerja per bit, add dan sub memakai penjumlah biner dengan negasi untuk sub, sedangkan slt memakai jalur sub dan memilih bit pertamanya melalui N XOR V internal. Nilai desimal pada keluaran hanya membantu pembacaan.
"""ALU kombinasional sederhana dengan status flag.
Operan berupa deretan 8 bit (bit paling rendah di indeks 0) yang menyandi
bilangan komplemen dua. Semua perhitungan memakai operasi bit.
"""
LEBAR = 8
def ke_bit(n, lebar=LEBAR):
"""Mengubah bilangan komplemen dua menjadi deretan bit (untuk menyiapkan masukan)."""
u = n & ((1 << lebar) - 1)
return [(u >> i) & 1 for i in range(lebar)]
def dari_bit(bits):
"""Membaca deretan bit komplemen dua sebagai bilangan bertanda (untuk tampilan)."""
nilai = 0
for i in range(len(bits) - 1, -1, -1):
nilai = (nilai << 1) | bits[i]
if bits[-1]:
nilai -= 1 << len(bits)
return nilai
def tampil(bits):
"""Menampilkan deretan bit dalam urutan baca, bit tertinggi di kiri."""
return "".join(str(b) for b in reversed(bits))
def tambah(a_bits, b_bits):
"""Penjumlah biner: mengembalikan hasil, carry akhir, dan carry masuk bit tanda."""
hasil = []
carry = 0
carry_tanda = 0
for i in range(len(a_bits)):
carry_tanda = carry
s = a_bits[i] ^ b_bits[i] ^ carry
carry = (a_bits[i] & b_bits[i]) | (carry & (a_bits[i] ^ b_bits[i]))
hasil.append(s)
return hasil, carry, carry_tanda
def negasi(bits):
"""Komplemen dua: balik semua bit, lalu tambah satu melalui perambatan carry."""
balik = [1 - b for b in bits]
hasil = []
carry = 1
for b in balik:
hasil.append(b ^ carry)
carry = carry & b
return hasil
def alu(a, b, op):
"""Menjalankan satu operasi ALU dan mengembalikan pasangan (hasil, flag)."""
if op == "and":
hasil = [x & y for x, y in zip(a, b)]
c = v = 0
elif op == "or":
hasil = [x | y for x, y in zip(a, b)]
c = v = 0
elif op == "add":
hasil, raw_carry, carry_tanda = tambah(a, b)
c, v = raw_carry, carry_tanda ^ raw_carry
elif op == "sub":
hasil, raw_carry, carry_tanda = tambah(a, negasi(b))
c, v = 1 - raw_carry, carry_tanda ^ raw_carry # C menjadi indikator pinjaman
elif op == "slt":
h, raw_carry, carry_tanda = tambah(a, negasi(b))
bit_slt = h[-1] ^ (carry_tanda ^ raw_carry) # N XOR V pada hasil internal
hasil = [bit_slt] + [0] * (len(a) - 1)
c = v = 0
else:
raise ValueError(f"operasi tidak dikenal: {op}")
flag = {
"Zero": int(all(bit == 0 for bit in hasil)),
"N": hasil[-1],
"C": c,
"V": v,
}
return hasil, flag
if __name__ == "__main__":
contoh = [
(100, 25, "and"),
(100, 25, "add"),
(100, 25, "sub"),
(100, 25, "slt"),
(-8, 7, "sub"),
(-8, 7, "slt"),
(100, 50, "add"),
(-128, -1, "add"),
]
for a, b, op in contoh:
hasil, flag = alu(ke_bit(a), ke_bit(b), op)
f = " ".join(f"{k}={v}" for k, v in flag.items())
print(f"a={a:>4} b={b:>4} {op:>3} -> {tampil(hasil)} ({dari_bit(hasil):>4}) {f}")a= 100 b= 25 and -> 00000000 ( 0) Zero=1 N=0 C=0 V=0
a= 100 b= 25 add -> 01111101 ( 125) Zero=0 N=0 C=0 V=0
a= 100 b= 25 sub -> 01001011 ( 75) Zero=0 N=0 C=0 V=0
a= 100 b= 25 slt -> 00000000 ( 0) Zero=1 N=0 C=0 V=0
a= -8 b= 7 sub -> 11110001 ( -15) Zero=0 N=1 C=0 V=0
a= -8 b= 7 slt -> 00000001 ( 1) Zero=0 N=0 C=0 V=0
a= 100 b= 50 add -> 10010110 (-106) Zero=0 N=1 C=0 V=1
a=-128 b= -1 add -> 01111111 ( 127) Zero=0 N=0 C=1 V=1Keluaran di atas memuat beberapa perilaku yang layak diperiksa satu per satu. AND dari 100 dan 25 menghasilkan 00000000, sehingga flag Zero menyala. Slt menjawab 0 untuk pasangan 100 dan 25, tetapi 1 untuk pasangan -8 dan 7, sesuai urutan bertandanya. Baris add kedua dari bawah memperlihatkan V=1 pada 100 + 50, dan hasilnya terbaca -106 karena meluber keluar rentang 8 bit. Baris paling bawah menunjukkan -128 + -1 yang juga meluber, dengan hasil 127 dan carry keluar 1 yang wajar bagi aritmetika tanpa tanda. Baris slt melaporkan C=0 dan V=0 karena operasinya bukan add atau sub, sedangkan keputusannya diambil dari N XOR V pada hasil pengurangan internal.
Ringkasan#
- ALU adalah blok kombinasional yang memilih satu operasi berdasarkan bit kontrol, lalu menerbitkan hasil dan flag bersamaan.
- Operasi minimumnya adalah and, or, add, sub, dan slt, dengan sub dihitung sebagai penjumlahan terhadap negasi operand.
- Flag Zero, N, C, dan V melaporkan sifat hasil, dan percabangan mengambil keputusannya dari flag tersebut.
- slt dihitung dari N XOR V pada hasil pengurangan, sehingga perbandingan bertanda tidak memerlukan rangkaian terpisah.
Referensi#
- RISC-V Instruction Set Manual — RISC-V International — Menetapkan perilaku instruksi slt dan percabangan RV32I yang menjadi rujukan bagian perbandingan.
- Computer Systems: A Programmer’s Perspective — Carnegie Mellon — Membahas ALU, flag, dan aritmetika bilangan bulat dari sudut pandang pemrogram.