Program counter adalah register khusus yang isinya alamat instruksi berikutnya. Komponen berukuran satu register inilah yang mengubah deretan instruksi yang diam di memori menjadi program yang berjalan berurutan. Topik ini membangun program counter di atas register biasa, membahas incremen otomatis dan pemuatan ulang alamat untuk lompatan, lalu menganimasikan seluruh siklusnya dengan Python pada program kecil yang berisi perulangan.
Register yang mengurutkan program#
Instruksi tersimpan di memori sebagai deretan kata yang bernomor alamat, dan prosesor mengeksekusinya satu demi satu. Program counter (PC) memegang alamat instruksi berikutnya, sehingga urutan eksekusi sepenuhnya ditentukan oleh nilai satu register ini. Setiap tepi clock, PC diperbarui menjadi alamat instruksi sesudahnya, yang biasanya berarti alamat lama ditambah satu. Penambahan satu ini disebut incremen, dan karena dilakukan otomatis oleh perangkat keras, deretan instruksi yang berurutan di memori langsung berjalan berurutan pula.
Kata “khusus” pada nama register khusus menunjuk pada sambungan tambahannya. PC bukan register biasa yang hanya menunggu nilai dari luar, melainkan register yang diberi penambah (incrementer) tersendiri beserta jalur muat untuk menimpanya. Dua jalur itulah seluruh mekanisme pengendalian alur program, yaitu incremen menggeser eksekusi maju satu langkah, sedangkan pemuatan ulang mengirim eksekusi ke alamat mana pun yang diminta. Register umum di dalam CPU dan PC memang dibuat dari blok flip-flop yang sama, dan perbedaan keduanya terletak pada sambungan ini, bukan pada jenis penyimpannya.
Siklus fetch, incremen, dan jalankan#
Satu langkah eksekusi dapat dipecah menjadi tiga tahap yang selesai dalam satu tepi clock. Tahap fetch membaca dari memori instruksi yang alamatnya ditunjuk PC. Tahap incremen memperbarui PC menjadi alamat berikutnya. Tahap execute menjalankan isi instruksi itu, apakah menghitung, memindahkan data, atau memodifikasi PC sekali lagi untuk lompatan. Model tiga tahap ini adalah penyederhanaan yang disengaja, karena perangkat keras nyata menumpuk tahap-tahap tersebut dengan cara yang lebih halus.
# tidak-dijalankan
instruksi = memori.baca(pc) # fetch: ambil instruksi pada alamat PC
pc = pc + 1 # incremen: alamat instruksi berikutnya
jalankan(instruksi) # execute: lakukan isi instruksinyaUrutan fetch terlebih dahulu baru incremen penting dipahami dengan tepat. Instruksi dibaca sebelum PC berubah, sehingga PC selalu menunjuk instruksi yang sedang diambil, bukan yang sudah terlewat. Apabila urutannya dibalik, satu instruksi akan terlewat pada setiap tepi, dan program dengan lebih dari satu instruksi pasti berjalan keliru. Perhatikan pula bahwa incremen terjadi tanpa memandang isi instruksi, karena keputusan untuk melompat ditangani secara terpisah oleh jalur muat. Kesederhanaan ini membuat jejak PC mudah dibaca, karena setiap baris tabel berkorespondensi dengan satu keputusan yang pasti.
Lompatan dan pemuatan ulang alamat#
Program yang hanya berjalan lurus tidak cukup untuk pekerjaan apa pun, sehingga dua operasi lompatan melengkapi incremen. Lompatan tak bersyarat menimpa PC dengan alamat tujuan, sedangkan lompatan bersyarat menimpanya hanya bila syarat terpenuhi, misalnya bila sebuah register masih bernilai positif. Kedua operasi ini bekerja dengan sinyal load yang sudah dikenal pada register biasa, yaitu alamat tujuan diteruskan ke masukan PC dan load diaktifkan pada tepi itu. Selama load nonaktif, incremen berjalan seperti biasa tanpa terganggu.
Perulangan lahir dari kombinasi incremen dan lompatan bersyarat. Instruksi di akhir badan perulangan melompat kembali ke awal selama syarat masih terpenuhi, dan eksekusi jatuh lurus ke instruksi sesudahnya begitu syarat gagal. Struktur perulangan dan percabangan pada bahasa pemrograman tingkat tinggi dikompilasi menjadi persis pola ini. Perangkat keras dengan demikian hanya menyediakan dua kemampuan sederhana, yaitu maju satu dan melompat, sedangkan seluruh variasi alur program disusun dari keduanya.
Simulasi jejak program counter#
Model di bawah ini menjalankan program fiktif penghitung mundur berisi lima instruksi, lengkap dengan satu lompatan bersyarat. Setiap baris tabel adalah satu tepi clock, dengan PC sebelum fetch, instruksi yang diambil, PC sesudah keputusan, dan nilai register A. Nama instruksinya sengaja dibuat fiktif dan sederhana, sedangkan ISA (instruction set architecture), yaitu kontrak instruksi sebuah prosesor, dibahas pada modul bahasa mesin. PC dibuat 4 bit sehingga cukup menjangkau alamat, dan lima alamat program ini tidak pernah mendekati batas itu.
# Simulasi program counter di atas program fiktif berisi lima instruksi.
# Satu tepi clock menyelesaikan satu instruksi: fetch, incremen, jalankan.
class ProgramCounter:
"""Program counter 4 bit yang menahan alamat instruksi berikutnya."""
MASK = 0xF # lima alamat program cukup dijangkau 4 bit
def __init__(self, alamat_awal=0):
self.nilai = alamat_awal
def incremen(self):
"""Geser PC satu alamat maju, tetap dalam 4 bit."""
self.nilai = (self.nilai + 1) & self.MASK
def muat(self, alamat):
"""Muat ulang PC dengan alamat tujuan lompatan."""
self.nilai = alamat & self.MASK
def jalankan(program):
"""Eksekusi program hingga instruksi BERHENTI dan cetak jejak PC per tepi."""
pc = ProgramCounter()
a = 0 # register A yang dipakai program penghitung mundur
print("tepi | PC sebelum | instruksi | PC sesudah | A")
print("-----+------------+-------------+------------+----")
tepi = 0
while True:
if tepi >= 100:
print("batas 100 tepi terlampaui, simulasi dihentikan")
break
alamat = pc.nilai # fetch: alamat instruksi berikutnya
nama, operand = program[alamat]
tepi += 1
if nama == "MUAT":
a = operand
pc.incremen()
elif nama == "TAMPILKAN":
pc.incremen() # nilai A terbaca pada kolom tabel
elif nama == "KURANGI":
a = (a - operand) & 0xFF
pc.incremen()
elif nama == "LOMPAT-JIKA" and a > 0:
pc.muat(operand) # lompatan bersyarat: pemuatan ulang alamat
elif nama == "LOMPAT-JIKA":
pc.incremen() # syarat gagal, incremen berjalan seperti biasa
elif nama == "BERHENTI":
print(f"{tepi:4d} | {alamat:10d} | {nama:11s} | {pc.nilai:10d} | {a:3d}")
break
print(f"{tepi:4d} | {alamat:10d} | {nama:11s} | {pc.nilai:10d} | {a:3d}")
program = [
("MUAT", 3), # alamat 0: A = 3
("TAMPILKAN", 0), # alamat 1: tampilkan A
("KURANGI", 1), # alamat 2: A = A - 1
("LOMPAT-JIKA", 1), # alamat 3: lompat ke alamat 1 bila A > 0
("BERHENTI", 0), # alamat 4: berhenti
]
print("Program penghitung mundur dari 3\n")
jalankan(program)Program penghitung mundur dari 3
tepi | PC sebelum | instruksi | PC sesudah | A
-----+------------+-------------+------------+----
1 | 0 | MUAT | 1 | 3
2 | 1 | TAMPILKAN | 2 | 3
3 | 2 | KURANGI | 3 | 2
4 | 3 | LOMPAT-JIKA | 1 | 2
5 | 1 | TAMPILKAN | 2 | 2
6 | 2 | KURANGI | 3 | 1
7 | 3 | LOMPAT-JIKA | 1 | 1
8 | 1 | TAMPILKAN | 2 | 1
9 | 2 | KURANGI | 3 | 0
10 | 3 | LOMPAT-JIKA | 4 | 0
11 | 4 | BERHENTI | 4 | 0Baca jejaknya dari tepi 1 sampai 11. PC naik satu per satu pada instruksi biasa, melompat dari 3 ke 1 selama register A masih positif, dan jatuh lurus ke 4 begitu A mencapai 0. Tepi 10 adalah momen kuncinya, yaitu lompatan bersyarat yang syaratnya gagal, sehingga incremen berjalan seperti biasa dan program berakhir pada instruksi BERHENTI. Sebelas tepi memproses lima instruksi karena tiga instruksi di dalam badan perulangan dieksekusi tiga kali, dan penghitungan semacam ini menjadi dasar membaca biaya program yang berulang.
Ringkasan#
- Program counter adalah register yang isinya alamat instruksi berikutnya, sehingga urutan eksekusi ditentukan oleh satu nilai tunggal.
- Incremen otomatis menggeser PC satu alamat per tepi, sedangkan pemuatan ulang melalui sinyal load menimpanya untuk lompatan.
- Urutan fetch sebelum incremen menjaga konsistensi antara instruksi yang sedang diambil dan alamat yang ditunjuk PC.
- Perulangan dan percabangan pada tingkat mesin tersusun dari incremen dan lompatan bersyarat.
Referensi#
- Nand to Tetris — Shimon Schocken dan Noam Nisan — Proyek pembelajaran yang membangun program counter dan CPU yang mampu mengeksekusi program nyata.
- Computation Structures — MIT OpenCourseWare — Mata kuliah yang membahas pengurutan eksekusi instruksi dan mekanisme lompatan pada prosesor.