Datapath Siklus Tunggal

Jalur kabel yang menjalankan fetch, decode, dan execute dalam satu komponen utuh dan satu clock.

Daftar isi

Datapath adalah jaringan kabel dan komponen di dalam prosesor yang membawa data satu instruksi dari tempat penyimpanannya menuju perhitungan, lalu kembali ke tempat hasilnya diterima. Topik ini merakit program counter, memori, register file, ALU, dan mux menjadi satu datapath siklus tunggal yang utuh, tanpa menambahkan komponen penyimpan baru. Simulasi Python kemudian mengeksekusi empat instruksi fiktif pada jalur itu dan mencetak PC, instruksi, hasil ALU, serta register tujuan pada setiap langkah, sehingga perjalanan data di dalam kabel dapat diikuti nilai demi nilai.

Komponen datapath dan jalurnya#

Tujuh komponen menyusun datapath pada topik ini. Program counter (PC) menahan alamat instruksi yang sedang dijalankan. Memori instruksi menyimpan deretan kata instruksi dan membacanya pada alamat yang dikirim PC. Register file, yaitu kumpulan register umum dengan dua pintu baca dan satu pintu tulis, menyediakan operand untuk perhitungan dan menerima hasilnya. ALU menghitung penjumlahan dan pengurangan sesuai jenis instruksinya. Memori data menyimpan nilai yang dapat dibaca oleh load dan ditulis oleh store. Penambah menghitung PC ditambah satu secara terus-menerus, sedangkan mux (multiplexer), yaitu rangkaian pemilih satu dari beberapa masukan, menentukan nilai mana yang diteruskan keluar.

Kabelnya mengikuti alur yang tetap untuk semua instruksi. PC mengirim alamatnya ke memori instruksi sekaligus ke penambah, dan keluaran penambah menjadi salah satu masukan mux PC. Instruksi yang terbaca mengalir ke register file, dan field, yaitu bagian kata instruksi yang menyimpan satu nilai, menunjuk dua register yang dibaca sekaligus. Kedua operand mengalir ke ALU, sedangkan hasil ALU memiliki dua tujuan, yaitu mux tulis balik yang kembali ke register file dan memori data yang menggunakannya sebagai alamat. Diagram berikut merangkum seluruh jalur tersebut.

PC berikutnyajika nol: pilih alamat cabangABdata tulisalamathasil ALUtulis balikPCMemoriInstruksiRegister File2 baca, 1 tulisALUMemori DataPenambah +1MuxMux
Datapath siklus tunggal dengan PC, memori instruksi, register file, ALU, memori data, penambah, dan dua mux

Diagram memuat dua mux yang menjadi titik keputusan utama. Mux di dekat PC memilih antara PC berikutnya dari penambah dan alamat cabang, sedangkan mux tulis balik memilih antara hasil ALU dan data yang dibaca dari memori data. Garis putus-putus dari arah ALU ke mux PC membawa keputusan cabang, yaitu sinyal yang menyala ketika pengurangan dua operand menghasilkan nol. Satu penyederhanaan perlu dicatat, yaitu masukan offset untuk load dan store tidak digambar sebagai jalur tersendiri, karena fokus diagram adalah jalur utama yang dilalui setiap instruksi.

Satu clock untuk satu instruksi#

Prinsip siklus tunggal terdengar sesederhana namanya, yaitu satu instruksi selesai dalam satu periode clock, mulai dari fetch, yaitu pengambilan instruksi, hingga penulisan hasilnya. Tidak ada tahap yang ditunda dan dilanjutkan pada clock berikutnya, karena seluruh jalur aktif bersamaan dan nilai mengalir dari ujung masuk ke ujung keluar dalam satu putaran. Setiap instruksi menggunakan clock yang sama panjang meskipun jalur kabel yang dilaluinya berbeda. Instruksi add selesai di mux tulis balik, sedangkan load harus melewati memori data lagi sebelum hasilnya sampai ke register file.

Perbedaan panjang jalur itulah yang menentukan kecepatan seluruh prosesor. Periode clock TclockT_{\text{clock}} minimal sebesar jumlah waktu tempuh jalur terlambat, dan jalur terlambat pada datapath ini adalah load, yaitu waktu PC, memori instruksi, register file, ALU, memori data, dan mux tulis balik yang dijumlahkan menjadi Tclock≥tPC+tinstr+treg+tALU+tdata+tmuxT_{\text{clock}} \ge t_{PC} + t_{\text{instr}} + t_{\text{reg}} + t_{\text{ALU}} + t_{\text{data}} + t_{\text{mux}}. Instruksi dengan jalur pendek tetap menggunakan periode yang sama, sehingga sebagian waktunya terbuang menunggu tepi clock. Kelemahan ini kelak dibenahi oleh pipelining, yang memecah siklus menjadi tahap-tahap pendek yang berjalan bertumpuk.

Menyusun jalur data pada simulasi#

Simulasi memodelkan ISA (instruction set architecture) fiktif 16 bit, yaitu kontrak instruksi yang hanya berlaku di dalam topik ini. Setiap kata instruksi 16 bit terbagi menjadi opcode, yaitu kode operasi instruksi, selebar 4 bit pada posisi tertinggi, tiga field register selebar 3 bit, dan field offset selebar 6 bit pada posisi terendah. Opcode membedakan empat instruksi, yaitu add untuk penjumlahan register, load untuk membaca memori data, store untuk menulisnya, dan beq untuk membandingkan dua register lalu bercabang bila sama. Nilai offset ditafsirkan bertanda, sehingga cabang mundur pun dapat dinyatakan.

Keadaan awal mesin sudah disiapkan sebelum instruksi pertama berjalan. Register R2 berisi 10 dan R3 berisi 5, sedangkan memori data sudah menyimpan nilai 15 pada alamat 17 sebagai sisa perhitungan yang lebih awal. Program berisi empat instruksi yang menggunakan keempat jenisnya, dimulai dari penjumlahan, dilanjutkan pemuatan nilai tersimpan itu, penyimpanan hasilnya ke alamat lain, dan diakhiri perbandingan antara hasil hitungan dan nilai yang dimuat. Jalankan berkas berikut untuk melihat jalurnya bekerja.

python datapath.py
"""Simulasi datapath siklus tunggal untuk ISA fiktif 16 bit.

Komponen utama disimulasikan sesungguhnya: PC, memori instruksi,
register file, ALU, memori data, dan mux. Program memuat empat
instruksi fiktif: add, load, store, dan beq.
"""

NAMA_OP = {1: "add", 3: "load", 4: "store", 5: "beq"}


def enc_add(rd, rs1, rs2):
    return (1 << 12) | (rd << 9) | (rs1 << 6) | (rs2 << 3)


def enc_load(rd, rs1, off):
    return (3 << 12) | (rd << 9) | (rs1 << 6) | (off & 0x3F)


def enc_store(rs, rs1, off):
    return (4 << 12) | (rs << 9) | (rs1 << 6) | (off & 0x3F)


def enc_beq(rs1, rs2, off):
    return (5 << 12) | (rs2 << 9) | (rs1 << 6) | (off & 0x3F)


def decode(instr):
    """Memecah kata 16 bit menjadi field sesuai posisi bitnya."""
    op = (instr >> 12) & 0xF
    a = (instr >> 9) & 0x7
    b = (instr >> 6) & 0x7
    c = (instr >> 3) & 0x7
    raw = instr & 0x3F
    off = raw - 64 if raw & 0x20 else raw
    return op, a, b, c, off


# Keadaan awal mesin: register file dan memori data.
R = [0] * 8
R[2], R[3] = 10, 5
MEM = {17: 15}  # mem[17] sudah berisi 15 sebagai sisa perhitungan sebelumnya

# Memori instruksi: empat kata 16 bit.
PROGRAM = [
    enc_add(1, 2, 3),    # 0: add   R1, R2, R3
    enc_load(4, 1, 2),   # 1: load  R4, R1, 2
    enc_store(4, 1, 3),  # 2: store R4, R1, 3
    enc_beq(1, 4, 2),    # 3: beq   R1, R4, 2
]

pc = 0
langkah = 0
while pc < len(PROGRAM):
    langkah += 1
    instr = PROGRAM[pc]                # memori instruksi membaca alamat PC
    op, a, b, c, off = decode(instr)   # field dipecah dari posisi bit
    print(f"== Langkah {langkah} | PC={pc} | 0x{instr:04X} ({NAMA_OP[op]}) ==")
    if op == 1:                        # add rd, rs1, rs2
        print(f"   baca    : R{b}={R[b]}, R{c}={R[c]}")
        hasil = R[b] + R[c]
        print(f"   ALU     : {R[b]} + {R[c]} = {hasil}")
        print(f"   tulis   : R{a} <- {hasil}")
        R[a] = hasil                   # register file menulis di akhir siklus
    elif op == 3:                      # load rd, offset(rs1)
        alamat = R[b] + off
        print(f"   baca    : R{b}={R[b]}")
        print(f"   ALU     : {R[b]} + {off} = {alamat} (alamat)")
        print(f"   memori  : mem[{alamat}] = {MEM[alamat]}")
        print(f"   tulis   : R{a} <- {MEM[alamat]}")
        R[a] = MEM[alamat]
    elif op == 4:                      # store rs, offset(rs1)
        alamat = R[b] + off
        print(f"   baca    : R{b}={R[b]}, R{a}={R[a]}")
        print(f"   ALU     : {R[b]} + {off} = {alamat} (alamat)")
        print(f"   memori  : mem[{alamat}] <- {R[a]}")
        MEM[alamat] = R[a]
    else:                              # beq rs1, rs2, offset
        print(f"   baca    : R{b}={R[b]}, R{a}={R[a]}")
        hasil = R[b] - R[a]
        print(f"   ALU     : {R[b]} - {R[a]} = {hasil} (uji nol)")
        if hasil == 0:
            print("   cabang  : hasil nol, mux PC memilih alamat cabang")
            pc_baru = pc + 1 + off
        else:
            print("   cabang  : hasil bukan nol, mux PC memilih PC+1")
            pc_baru = pc + 1
        print(f"   PC      : {pc} -> {pc_baru}")
        pc = pc_baru
        continue
    print(f"   PC      : {pc} -> {pc + 1}")
    pc += 1

print("Keadaan akhir:", ", ".join(f"R{i}={v}" for i, v in enumerate(R) if v), end="")
print(", " + ", ".join(f"mem[{k}]={MEM[k]}" for k in sorted(MEM)))
text Keluaran
== Langkah 1 | PC=0 | 0x1298 (add) ==
   baca    : R2=10, R3=5
   ALU     : 10 + 5 = 15
   tulis   : R1 <- 15
   PC      : 0 -> 1
== Langkah 2 | PC=1 | 0x3842 (load) ==
   baca    : R1=15
   ALU     : 15 + 2 = 17 (alamat)
   memori  : mem[17] = 15
   tulis   : R4 <- 15
   PC      : 1 -> 2
== Langkah 3 | PC=2 | 0x4843 (store) ==
   baca    : R1=15, R4=15
   ALU     : 15 + 3 = 18 (alamat)
   memori  : mem[18] <- 15
   PC      : 2 -> 3
== Langkah 4 | PC=3 | 0x5842 (beq) ==
   baca    : R1=15, R4=15
   ALU     : 15 - 15 = 0 (uji nol)
   cabang  : hasil nol, mux PC memilih alamat cabang
   PC      : 3 -> 6
Keadaan akhir: R1=15, R2=10, R3=5, R4=15, mem[17]=15, mem[18]=15

Membaca jejak eksekusi#

Empat langkah pada keluaran memperlihatkan empat jalur yang berbeda. Langkah pertama adalah add, yang membaca R2 dan R3 dari register file, menghitung 10 + 5 = 15 pada ALU, lalu menulis hasilnya ke R1 pada akhir siklus. Langkah kedua adalah load, yang menggunakan ALU bukan untuk menghitung hasil akhir melainkan untuk membentuk alamat, yaitu R1 + 2 = 17, kemudian memori data menyampaikan isinya dan mux tulis balik memilih nilai itu untuk masuk ke R4. Langkah ketiga adalah store, yang juga membentuk alamat dengan ALU, tetapi nilai yang ditulis ke mem[18] berasal dari register file melalui jalur data tulis, bukan dari hasil ALU.

Langkah keempat menutup program dengan beq. ALU mengurangkan R1 dengan R4 dan hasilnya 0, sehingga sinyal nol menyala dan mux PC memilih alamat cabang, bukan PC + 1 dari penambah. PC berpindah dari 3 ke 6, yaitu alamat di luar empat instruksi program, sehingga simulasi berakhir di sana. Baris keadaan akhir mengonfirmasi bahwa setiap tulisan sampai ke tempatnya, yaitu R1 dan R4 sama-sama berisi 15, sedangkan mem[18] berisi 15 hasil penyimpanan pada langkah ketiga. Ketiga nilai itu adalah bukti bahwa jalur tulis register dan jalur tulis memori keduanya bekerja.

Kesalahan umum#

  • Menghitung ulang panjang clock untuk setiap instruksi. Clock pada datapath siklus tunggal bersifat tunggal untuk semua instruksi, sehingga periodenya diset dari jalur terlambat, yaitu load. Clock yang dikecilkan mengikuti jalur add akan memotong jalur load di tengah, dan datanya tidak pernah tiba di register file.
  • Menyambung alamat cabang langsung ke PC tanpa mux. PC akan melompat pada setiap beq, termasuk ketika perbandingannya tidak sama. Perbaikannya, alamat cabang hanya menjadi salah satu masukan mux PC, sedangkan sinyal nol dari ALU yang memilihnya.
  • Menulis hasil ALU ke register file pada instruksi load. Nilai yang seharusnya masuk register adalah isi memori data, bukan alamatnya. Mux tulis balik hadir persis untuk keputusan ini, dan pemilihnya mengikuti jenis instruksi yang sedang berjalan.
  • Menganggap simulasi gagal ketika PC melompat ke alamat 6. Pada jejak, alamat itu berada di luar empat instruksi program, sehingga perulangan eksekusi berhenti karena tidak ada instruksi yang tersisa. Pada mesin nyata, memori berisi instruksi lain setelahnya, dan kejadian serupa hanya berarti program melanjutkan ke bagian yang tidak dicetak.

Ringkasan#

  • Datapath siklus tunggal menyatukan PC, memori instruksi, register file, ALU, memori data, penambah, dan mux menjadi satu jalur yang menyelesaikan satu instruksi dalam satu clock.
  • Panjang clock ditentukan oleh jalur terlambat, yaitu load, sehingga instruksi lain tetap menggunakan periode yang sama meskipun jalurnya lebih pendek.
  • Dua mux menampung keputusan terpenting, yaitu mux PC yang memilih antara PC + 1 dan alamat cabang, serta mux tulis balik yang memilih antara hasil ALU dan data memori.
  • Simulasi empat instruksi memperlihatkan peran ALU yang berbeda pada add, load, store, dan beq dengan nilai yang dapat diikuti langkah demi langkah.

Referensi#