Satu Kabel vs Banyak Kabel
Sejauh ini setiap sinyal yang kita lihat lebarnya satu bit. Desain sungguhan hampir tidak pernah seperti itu: alamat lebarnya 16 atau 32 bit, bus data 8 atau 64, piksel RGB 24. Verilog memberimu satu mekanisme untuk membuat sinyal apa pun menjadi multi-bit: tambahkan rentang di dalam kurung siku.
wire [7:0] data; // 8-bit wire, bit 7 is MSB, bit 0 is LSB
reg [15:0] address; // 16-bit reg
output reg [31:0] result; // 32-bit module output
Angka di dalam kurung siku adalah posisi bit dari bit paling signifikan dan paling tidak signifikan. [7:0] berarti "sinyal ini punya bit bernomor 7 turun sampai 0", jadi totalnya 8 bit. Angka pertama adalah indeks tertinggi. Angka kedua yang terendah.
Sesekali kamu akan melihat [0:7]: jumlah bitnya sama, tapi urutannya terbalik saat dipotong. Bentuk [high:low] adalah konvensi yang sangat dominan di industri; tetaplah memakainya kecuali kamu punya alasan kuat untuk tidak melakukannya.
Contoh Lengkap: Adder 8-Bit
Setiap + menjumlahkan dua vektor 8-bit dan menghasilkan hasil 9-bit. Literal angka seperti 8'd10 berarti "nilai desimal 10 dengan lebar 8 bit"; kita akan membahasnya di Literal Angka.
Memotong: Mengambil Bit Tertentu
Begitu kamu punya vektor, kamu bisa mengambil bit satu per satu atau rentang yang berurutan:
Jangan terlalu memikirkan baris force di testbench; kita hanya butuh cara untuk menyuntikkan nilai demi memperagakan pemotongan. Bagian yang menarik adalah potongan-potongannya.
Beberapa aturan:
- Arah potongan harus sama dengan deklarasinya. Kalau kamu mendeklarasikan
[7:0], potong dengan[high:low]. Membalik arahnya adalah syntax error. - Memotong di luar rentang menghasilkan
x(tidak diketahui) di simulasi. Tool sintesis mungkin memberi peringatan atau error. - Pemilihan bit berbasis nol sesuai indeks yang kamu tulis:
data[0]adalah bit bernama0, yang (untuk deklarasi[7:0]) adalah LSB.
Potongan dengan Basis Variabel: +: dan -:
Kebutuhan yang umum: "beri aku 8 bit mulai dari bit N". Kamu tidak bisa langsung menulis data[N+7:N] karena Verilog mengharuskan kedua ujung rentang berupa konstanta. Sintaks yang menyelesaikan masalah ini:
data[base +: width] // width bits starting at `base`, going UP
data[base -: width] // width bits starting at `base`, going DOWN
Lebarnya konstan (kita mengambil 8 bit sekaligus), tapi basisnya bisa berupa ekspresi saat runtime. Itulah yang kamu butuhkan untuk memori yang dialamatkan per byte, tap pada shift register, dan sejenisnya.
Array: Selangkah Setelah Vektor
Vektor adalah satu sinyal multi-bit. Array adalah kumpulan vektor yang diindeks secara independen:
reg [31:0] mem [0:1023];
Deklarasi itu punya dua rentang, dan keduanya punya arti yang berbeda:
[31:0]adalah dimensi packed: lebar setiap word.[0:1023]adalah dimensi unpacked: berapa banyak word yang ada.
Jadi mem adalah 1024 register 32-bit yang terpisah. Kamu mengakses salah satunya dengan satu indeks:
mem[5] = 32'hCAFE_BABE; // write word 5
data = mem[address]; // read the word at `address`
Itu adalah memori kecil yang berisi bilangan kuadrat. Desain sungguhan memakai pola yang sama untuk menyimpan register file, tabel lookup, FIFO, dan penyimpanan lain di dalam chip yang lebih besar dari satu vektor.
Packed vs Unpacked: Kenapa Ini Penting
Pembagian antara dimensi packed dan unpacked muncul di mana-mana. Tahu mana yang mana akan menghemat banyak waktu debug:
- Vektor packed adalah satu sinyal. Kamu bisa memperlakukan seluruhnya sebagai angka:
data + 1berfungsi,data == 32'h0berfungsi,data[7:0]berfungsi. - Array unpacked adalah banyak sinyal. Kamu tidak bisa memperlakukan seluruhnya sebagai angka:
mem + 1adalah syntax error. Kamu harus mengambil word tertentu dulu.
Beberapa dimensi packed sekaligus juga sah:
reg [3:0][7:0] regs; // 4 bytes packed together into a 32-bit signal
regs[0] adalah satu byte (byte terendah). regs secara keseluruhan selebar 32 bit. SystemVerilog banyak memakai bentuk ini.
Beberapa dimensi unpacked sekaligus membuat memori 2D:
reg [31:0] frame [0:479][0:639]; // 480x640 of 32-bit pixels
Kamu mengakses satu piksel dengan frame[y][x]. Beginilah bentuk buffer gambar di HDL.
Selanjutnya
Sekarang kamu bisa mendeklarasikan dan mengolah sinyal selebar apa pun yang kamu butuhkan. Dokumen berikutnya, Parameter, menunjukkan cara membuat lebar itu bisa dikonfigurasi, sehingga module yang sama bekerja dengan 8 bit di satu instance dan 32 bit di instance lain. Setelah itu kita lanjut ke aturan menulis angka literal (8'b1010_1100, 32'hDEAD_BEEF), dan nilai x/z yang muncul setiap kali ada sesuatu yang tidak digerakkan.
Pertanyaan yang sering diajukan
Apa itu vektor di Verilog?
Vektor adalah sinyal multi-bit. Kamu mendeklarasikannya dengan menambahkan rentang pada wire atau reg: wire [7:0] data adalah wire 8-bit. Angka di dalam kurung siku adalah posisi bit; dalam contoh ini bit 7 adalah yang paling signifikan dan bit 0 yang paling tidak signifikan. Kamu bisa mengambil satu bit (data[3]) atau rentang yang berurutan (data[7:4]).
Apa arti [7:0] di Verilog?
[7:0] mendeklarasikan rentang dari bit 7 turun sampai bit 0, inklusif: sinyal 8-bit dengan bit 7 sebagai bit paling signifikan. Angka pertama adalah indeks tertinggi, angka kedua yang terendah. Kamu juga bisa menulis [0:7] untuk pengindeksan little-endian, tapi bentuk [high:low] jauh lebih umum dipakai di kode industri.
Bagaimana cara memotong bit di Verilog?
Pakai indeks dengan kurung siku. data[3] mengambil satu bit. data[7:4] mengambil empat bit teratas sebagai vektor 4-bit. Arah potongan harus sama dengan deklarasinya: kalau kamu mendeklarasikan [7:0], potong dengan [high:low]. SystemVerilog juga menambahkan data[3 +: 4] untuk potongan dengan basis variabel dan lebar konstan.
Apa perbedaan array packed dan unpacked di Verilog?
Array packed adalah satu bus yang berurutan: reg [31:0] word adalah satu sinyal 32-bit. Array unpacked (atau 'memori') adalah kumpulan word yang saling independen: reg [31:0] mem [0:1023] adalah 1024 register 32-bit yang terpisah. Kamu bisa membaca atau menulis satu word utuh dari array unpacked, tapi tidak bisa mengoperasikan seluruh array itu sebagai satu sinyal.
Bagaimana cara mendeklarasikan memori di Verilog?
reg [31:0] mem [0:1023]; mendeklarasikan memori berisi 1024 entri, masing-masing selebar 32 bit. Kurung siku pertama adalah lebar word (packed); yang kedua adalah jumlah word (unpacked). Akses satu entri dengan mem[address], dan kamu bisa membaca atau menulis potongan dari entri itu dengan mem[address][7:0] setelah pengindeksan SystemVerilog-2005 diaktifkan.