Manufaktur industri
Industri Internet of Things | bahan industri | Pemeliharaan dan Perbaikan Peralatan | Pemrograman industri |
home  MfgRobots >> Manufaktur industri >  >> Industrial programming >> VHDL

Cara membuat testbench berbasis Tcl untuk modul kunci kode VHDL

Kebanyakan simulator VHDL menggunakan Tool Command Language (Tcl) sebagai bahasa scripting mereka. Saat Anda mengetik perintah di konsol simulator, Anda menggunakan Tcl. Selanjutnya, Anda dapat membuat skrip dengan Tcl yang berjalan di simulator dan berinteraksi dengan kode VHDL Anda.

Dalam artikel ini, kami akan membuat testbench pemeriksaan mandiri yang menggunakan Tcl alih-alih VHDL untuk memverifikasi bahwa modul VHDL berfungsi dengan benar.

Lihat juga:
Mengapa Anda perlu mempelajari Tcl
testbench Interaktif menggunakan Tcl

Anda dapat mengunduh kode dari artikel ini dan proyek ModelSim menggunakan formulir di bawah ini.

DUT:Modul kunci kode dalam VHDL

Sebelum kita mulai di testbench, saya akan mempresentasikan perangkat yang sedang diuji (DUT). Ini akan menjadi modul kunci kode yang akan membuka kunci brankas saat kita memasukkan urutan nomor yang benar pada papan PIN.

Orang sering menyebut kunci kode sebagai kunci kombinasi . Namun, menurut saya istilah ini kurang tepat. Tidak cukup memasukkan kombinasi angka yang benar untuk membukanya. Anda juga harus memasukkannya dalam urutan yang benar. Sebenarnya, kunci kombinasi sebenarnya adalah kunci permutasi , tapi sebut saja kunci kode .

Gambar di atas menunjukkan seperti kode kunci berupa brankas hotel. Untuk mempermudah, contoh kita hanya akan menggunakan tombol angka, dan bukan tombol “CLEAR” dan “LOCK”.

Cara kerja modul kunci kode

Modul kami akan mulai dalam posisi terkunci, dan jika kami memasukkan empat digit berturut-turut yang cocok dengan kode PIN rahasia, itu akan membuka kunci brankas. Untuk menguncinya kembali, kita bisa memasukkan nomor lain yang salah. Jadi, kita perlu membuat detektor urutan di VHDL.

Bentuk gelombang di atas menunjukkan bagaimana modul kunci kode akan bekerja. Selain jam dan reset, ada dua sinyal input:input_digit dan input_enable . Modul akan mengambil sampel digit input saat pengaktifannya adalah '1' pada tepi jam yang naik.

Hanya ada satu keluaran dari modul ini:buka kunci sinyal. Bayangkan itu mengontrol mekanisme penguncian brankas atau semacam brankas. membuka sinyal hanya akan menjadi '1' hanya ketika pengguna telah memasukkan empat digit berturut-turut yang cocok dengan PIN yang benar. Dalam artikel ini, kami akan menggunakan 1234 sebagai kode sandi.

Entitas

Kode di bawah ini menunjukkan entitas modul kunci kode. Karena tujuan modul ini adalah untuk menjadi contoh sederhana DUT untuk testbench berbasis TCL kami, saya mengkodekan kode sandi rahasia menggunakan obat generik. Empat konstanta generik adalah desimal berkode biner (BCD) yang diwujudkan sebagai bilangan bulat dengan rentang terbatas.

entity code_lock is
  generic (pin0, pin1, pin2, pin3 : integer range 0 to 9);
  port (
    clk : in std_logic;
    rst : in std_logic;
    input_digit : in integer range 0 to 9;
    input_enable : in std_logic;
    unlock : out std_logic
  );
end code_lock;

Sama seperti kode sandi, input_digit sinyal juga merupakan tipe BCD. Input dan output lainnya adalah std_logics.

Wilayah deklaratif

Modul ini hanya memiliki satu sinyal internal:register geser yang berisi empat digit terakhir yang diketik pengguna. Namun, alih-alih menggunakan rentang BCD dari 0 hingga 9, kami membiarkan angka dari -1 hingga 9. Itu adalah 11 nilai yang mungkin.

type pins_type is array (0 to 3) of integer range -1 to 9;
signal pins : pins_type;

Kami harus menggunakan nilai reset yang bukan merupakan angka yang dapat dimasukkan pengguna, dan untuk itulah -1. Jika kami menggunakan rentang 0 hingga 9 untuk pin array, menyetel kode sandi rahasia ke 0000 awalnya akan membuka brankas. Dengan skema ini, pengguna secara eksplisit harus memasukkan empat 0.

Pelaksanaan

Di bagian atas wilayah arsitektur, saya telah menambahkan pernyataan bersamaan yang membuka kunci vault saat menyematkan sinyal cocok dengan konstanta generik. Kode di bawah ini kombinasional, tetapi karena pin sinyal clock, membuka sinyal hanya akan berubah di tepi naik jam.

unlock <= '1' when pins = (pin3, pin2, pin1, pin0) else '0';

Kode di bawah ini menunjukkan proses yang membaca input pengguna. Itu membuat register geser keluar dari pin sinyal dengan menggeser semua nilai saat input_enable adalah '1' pada tepi jam yang meningkat. Hasilnya adalah empat digit terakhir yang dimasukkan pengguna disimpan di pin larik.

PINS_PROC : process(clk)
begin
  if rising_edge(clk) then
    if rst = '1' then
      pins <= (others => -1);

    else

      if input_enable  = '1' then
        pins(0) <= input_digit;
        pins(1 to 3) <= pins(0 to 2);
      end if;

    end if;
  end if;
end process;

Meja tes VHDL

Pertama-tama, kita masih membutuhkan testbench VHDL dasar, meskipun kita menggunakan Tcl untuk verifikasi. Kode di bawah ini menunjukkan file VHDL lengkap. Saya telah membuat instance DUT dan membuat sinyal clock, tetapi hanya itu. Selain menghasilkan jam, testbench ini tidak melakukan apa-apa.

library ieee;
use ieee.std_logic_1164.all;

entity code_lock_tb is
end code_lock_tb;

architecture sim of code_lock_tb is

  constant clk_hz : integer := 100e6;
  constant clock_period : time := 1 sec / clk_hz;

  signal clk : std_logic := '1';
  signal rst : std_logic := '1';
  signal input_digit : integer range 0 to 9;
  signal input_enable : std_logic := '0';
  signal unlock : std_logic;

begin

  clk <= not clk after clock_period;

  DUT : entity work.code_lock(rtl)
    generic map (1,2,3,4)
    port map (
      clk => clk,
      rst => rst,
      input_digit => input_digit,
      input_enable => input_enable,
      unlock => unlock
    );

end architecture;

Tcl testbench

Kode Tcl dalam contoh ini hanya berfungsi dengan simulator ModelSim VHDL. Jika Anda ingin menggunakannya di Vivado, misalnya, Anda harus membuat beberapa perubahan. Itu karena menggunakan beberapa perintah yang khusus untuk simulator ini. Kelemahan menggunakan Tcl adalah kode Anda dikunci ke vendor simulator tertentu.

Sebagai referensi, saya merekomendasikan Tcl Developer Xchange, yang mencakup bahasa Tcl secara umum, dan Manual Referensi Perintah ModelSim, yang menjelaskan semua perintah khusus ModelSim.

Jika Anda telah menginstal ModelSim, Anda dapat mengunduh proyek contoh menggunakan formulir di bawah ini.

Menggunakan namespace

Hal pertama yang saya sarankan adalah membuat namespace Tcl. Itu ide yang bagus karena jika tidak, Anda mungkin secara tidak sengaja menimpa variabel global dari skrip Tcl Anda. Dengan membungkus semua kode Anda di namespace, Anda menghindari potensi kekacauan itu. Kami akan meletakkan semua kode Tcl yang kami tulis mulai sekarang di dalam codelocktb namespace, seperti yang ditunjukkan di bawah ini.

namespace eval ::codelocktb {

  # Put all the Tcl code in here

}

Di dalam namespace, kita harus memulai dengan memulai simulasi, seperti yang ditunjukkan di bawah ini. Kami melakukannya dengan vsim perintah, diikuti oleh perpustakaan dan nama entitas dari testbench VHDL. Itu akan memuat simulasi, tetapi tidak akan menjalankannya. Tidak ada waktu simulasi yang berlalu sampai kita menggunakan run perintah nanti dalam skrip. Saya juga ingin menyertakan pernyataan If yang akan memuat bentuk gelombang, jika ada.

# Load the simulation
vsim work.code_lock_tb

# Load the waveform
if {[file exists wave.do]} {
  do wave.do
}

Mendeklarasikan variabel namespace

Sekarang setelah kita memuat simulasi, kita dapat mulai berinteraksi dengan kode VHDL. Pertama, saya ingin membaca clock_period konstan dan kode sandi generik ke dalam lingkungan Tcl.

Dalam kode di bawah ini, saya menggunakan pemeriksaan khusus ModelSim perintah untuk membaca sinyal VHDL dan nilai konstan dalam Tcl. Kemudian, saya menggunakan perintah string dan daftar Tcl untuk mengekstrak nilai waktu dan satuan waktu. Kode Pin variabel menjadi daftar empat digit yang kita baca dari konstanta generik.

# Read the clock period constant from the VHDL TB
variable clockPeriod [examine clock_period]

# Strip the braces: "{10 ns}" => "10 ns"
variable clockPeriod [string trim $clockPeriod "{}"]

# Split the number and the time unit
variable timeUnits [lindex $clockPeriod 1]
variable clockPeriod [lindex $clockPeriod 0]

# Read the correct PIN from the VHDL generics
variable pinCode [examine dut.pin0 dut.pin1 dut.pin2 dut.pin3]

Perhatikan bahwa saya menggunakan gaya pengkodean yang berbeda dalam skrip Tcl daripada di kode VHDL. Alih-alih menggarisbawahi, saya menggunakan casing unta. Itu karena saya mengikuti panduan gaya Tcl. Tentu saja, tidak ada yang menghentikan Anda untuk menggunakan gaya yang sama di file Tcl dan VHDL jika itu yang Anda inginkan.

Juga, jika Anda telah menggunakan Tcl tanpa ruang nama, Anda mungkin tahu tentang kata kunci set, yang merupakan cara standar untuk mendefinisikan variabel di Tcl. Di sini, saya menggunakan kata kunci variabel yang lebih baru sebagai gantinya. Ini seperti variabel global yang terikat pada namespace saat ini, bukan pada cakupan global.

Akhirnya, kami mendeklarasikan variabel bernama errorCount dan inisialisasi ke 0, seperti yang ditunjukkan di bawah ini. Saat simulasi berjalan melalui kasus uji, kami akan menambahkannya setiap kali kami mendeteksi kesalahan. Pada akhirnya, kita dapat menggunakannya untuk menentukan apakah modul lulus atau gagal.

variable errorCount 0

Mencetak teks di ModelSim

Perintah puts adalah cara standar untuk mencetak teks ke konsol di Tcl. Tetapi metode ini bekerja dengan cara yang tidak menguntungkan di ModelSim. Versi Windows melakukan apa yang Anda harapkan; itu mencetak string ke konsol. Di versi Linux, di sisi lain, teks dikeluarkan di shell tempat Anda memulai ModelSim, dan bukan di konsol di dalam GUI.

Gambar di bawah menunjukkan apa yang terjadi ketika kita mengetik puts perintah di konsol ModelSim. Itu muncul di jendela terminal di belakang. Lebih buruk lagi, jika Anda memulai ModelSim menggunakan pintasan desktop, Anda tidak akan pernah melihat hasilnya karena shell disembunyikan.

Ada solusi untuk mengubah perilaku put memerintah. Anda dapat, misalnya, mendefinisikan ulang (Ya! Anda dapat melakukannya di Tcl) dan membuatnya berfungsi di kedua platform. Tetapi cara yang lebih mudah untuk mencetak teks ke konsol di Linux dan Windows adalah dengan menggunakan echo khusus ModelSim perintah.

Kami akan menggunakan prosedur Tcl kustom yang ditunjukkan di bawah ini untuk mencetak teks. Dan saat melakukannya, kami juga menambahkan pesan dengan waktu simulasi saat ini. Di ModelSim, Anda selalu bisa mendapatkannya menggunakan $now variabel global.

proc printMsg { msg } {
  global now
  variable timeUnits
  echo $now $timeUnits: $msg
}

Mensimulasikan siklus N jam

DUT adalah modul clock, artinya tidak ada yang terjadi di antara tepi clock yang naik. Oleh karena itu kami ingin mensimulasikan dalam langkah-langkah berdasarkan durasi siklus clock. Prosedur Tcl di bawah ini menggunakan clockPeriod dan Unit waktu variabel yang kami ambil dari kode VHDL sebelumnya untuk mencapai itu.

proc runClockCycles { count } {
  variable clockPeriod
  variable timeUnits

  set t [expr {$clockPeriod * $count}]
  run $t $timeUnits
}

Prosedur ini membutuhkan satu parameter:count . Kami mengalikannya dengan panjang satu periode clock untuk mendapatkan durasi N siklus clock. Terakhir, kami menggunakan ModelSim run perintah untuk mensimulasikan selama itu.

Memeriksa nilai sinyal dari Tcl

Dalam ModelSim, kita dapat membaca sinyal VHDL dari Tcl dengan menggunakan memeriksa memerintah. Kode di bawah ini menunjukkan prosedur Tcl yang kami gunakan untuk membaca nilai sinyal dan memeriksa apakah itu seperti yang diharapkan. Jika sinyal tidak sesuai dengan expectedVal parameter, kami mencetak pesan jahat dan menambah errorCount variabel.

proc checkSignal { signalName expectedVal } {
  variable errorCount

  set val [examine $signalName]
  if {$val != $expectedVal} {
    printMsg "ERROR: $signalName=$val (expected=$expectedVal)"
    incr errorCount
  }
}

Menguji urutan PIN

Output dari modul kunci kode tidak hanya bergantung pada input saat ini tetapi juga pada nilai sebelumnya. Oleh karena itu, pemeriksaan output harus dilakukan setidaknya setelah mengirimkan empat digit ke DUT. Baru setelah itu sinyal buka kunci akan berubah dari '0' menjadi '1' jika PIN benar.

Prosedur Tcl di bawah ini menggunakan ModelSim force kata kunci untuk mengubah sinyal VHDL dari Tcl. -deposit beralih ke force kata kunci berarti ModelSim akan mengubah nilainya, tetapi biarkan driver VHDL lain yang mengendalikannya nanti, meskipun tidak ada entitas lain yang mengontrol input DUT di testbench kami.

proc tryPin { digits } {
  variable pinCode

  set pinStatus "incorrect"
  if { $digits == $pinCode } {
    set pinStatus "correct"
  }

  printMsg "Entering $pinStatus PIN code: $digits"

  foreach i $digits {
    force input_digit $i -deposit
    force input_enable 1 -deposit
    runClockCycles 1
    force input_enable 0 -deposit
    runClockCycles 1
  }

  if { $pinStatus == "correct" } {
    checkSignal unlock 1
  } else {
    checkSignal unlock 0
  }
}

tryPin prosedur menggunakan printMsg . kami prosedur untuk menginformasikan tentang apa yang dilakukannya, kode PIN mana yang dimasukkan, dan apakah itu kode sandi yang benar. Itu juga menggunakan runClockCycles prosedur untuk dijalankan tepat satu periode clock, sambil memanipulasi input DUT untuk mensimulasikan pengguna memasukkan PIN.

Terakhir, ia menggunakan checkSignal prosedur untuk memverifikasi bahwa DUT berperilaku seperti yang diharapkan. Seperti yang sudah saya jelaskan, checkSignal prosedur akan mencetak pesan kesalahan dan menambah errorCount variabel jika membuka sinyal tidak sesuai dengan nilai yang diharapkan.

Uji kasus dan status selesai

Dalam kode Tcl di atas, kami telah memulai simulasi, dan kami telah mendefinisikan banyak variabel dan prosedur, tetapi kami belum melakukan simulasi sama sekali. Simulasi masih pada 0 ns. Tidak ada waktu simulasi yang terlewat.

Menjelang akhir namespace kustom kami, kami mulai memanggil prosedur Tcl. Seperti yang ditunjukkan pada kode di bawah ini, kita mulai dengan menjalankan sepuluh siklus clock. Setelah itu, kami melepaskan pengaturan ulang dan memeriksa apakah tombol membuka output memiliki nilai yang diharapkan '0'.

runClockCycles 10

# Release reset
force rst '0' -deposit
runClockCycles 1

# Check reset value
printMsg "Checking reset value"
checkSignal unlock 0

# Try a few corner cases
tryPin {0 0 0 0}
tryPin {9 9 9 9}
tryPin $pinCode
tryPin [lreverse $pinCode]

if { $errorCount == 0 } {
  printMsg "Test: OK"
} else {
  printMsg "Test: Failure ($errorCount errors)"
}

Kami dapat mencoba semua 10.000 kode PIN yang berbeda, tetapi itu akan memakan banyak waktu. Simulasi berbasis Tcl jauh lebih lambat daripada testbench VHDL murni. Simulator harus banyak memulai dan berhenti, dan itu membutuhkan banyak waktu. Oleh karena itu, saya memutuskan hanya untuk memeriksa kasus sudut.

Kami memanggil tryPin empat kali, dengan kode PIN:0000, 9999, PIN yang benar, dan nomor dari PIN yang benar dalam urutan yang berlawanan. Saya membayangkan bahwa ini adalah kesalahan yang mudah dilakukan saat membuat kunci kode, hanya melihat kombinasinya, dan bukan urutan angkanya.

Terakhir, di akhir kode Tcl, tetapi masih di dalam namespace, kami memeriksa errorCount variabel dan cetak "Test:OK" atau "Test Failure".

Menjalankan testbench

Dan sekarang sampai pada bagian yang menyenangkan:menjalankan testbench. Saya lebih suka menggunakan perintah sumber Tcl, seperti yang ditunjukkan di bawah ini, tetapi Anda juga dapat menggunakan do khusus ModelSim memerintah. Faktanya, file ModelSim DO sebenarnya hanyalah file Tcl dengan akhiran yang berbeda.

source code_lock/code_lock_tb.tcl

Dalam versi final kode saya, tidak ada kesalahan. Daftar di bawah ini menunjukkan output dari simulasi yang berhasil. Skrip Tcl memberi tahu kami tentang apa yang dilakukannya, dan kami dapat melihat bahwa semua baris pesan memiliki stempel waktu. Itu printMsg kami prosedur di tempat kerja. Akhirnya, testbench berhenti dan mencetak “Test:OK”.

VSIM> source code_lock/code_lock_tb.tcl
# vsim 
...
# 110 ns: Checking reset value
# 110 ns: Entering incorrect PIN code: 0 0 0 0
# 190 ns: Entering incorrect PIN code: 9 9 9 9
# 270 ns: Entering correct PIN code: 1 2 3 4
# 350 ns: Entering incorrect PIN code: 4 3 2 1
# 430 ns: Test: OK

Namun, saya ingin menunjukkan kepada Anda seperti apa saat DUT gagal dalam tes. Untuk melakukan itu, saya telah membuat kesalahan dalam modul kunci kode. Saya telah mengganti pemeriksaan pin1 dengan pin2 sehingga DUT mengabaikan pin1 nilai. Sangat mudah untuk membuat kesalahan ketik, seperti yang ditunjukkan pada kode di bawah ini.

unlock <= '1' when pins = (pin3, pin2, pin2, pin0) else '0';

Saat kami menjalankan testbench, Anda dapat melihat dari daftar di bawah ini bahwa kesalahan terdeteksi. Dan akhirnya, testbench mencetak “Test:Failure” bersama dengan jumlah kesalahan.

VSIM> source code_lock/code_lock_tb.tcl
# vsim 
...
# 110 ns: Checking reset value
# 110 ns: Entering incorrect PIN code: 0 0 0 0
# 190 ns: Entering incorrect PIN code: 9 9 9 9
# 270 ns: Entering correct PIN code: 1 2 3 4
# 350 ns: ERROR: unlock=0 (expected=1)
# 350 ns: Entering incorrect PIN code: 4 3 2 1
# 430 ns: Test: Failure (1 errors)

Pemikiran terakhir

Saya telah membuat banyak testbenches berbasis Tcl dalam karir saya, tetapi pendapat saya tentang mereka agak terbagi.

Di satu sisi, Anda dapat melakukan beberapa hal keren yang tidak mungkin dilakukan dengan VHDL saja. Misalnya, testbench interaktif. Anda juga dapat mengubah testbench tanpa harus mengkompilasi ulang. Dan akhirnya, verifikasi menggunakan bahasa yang sangat berbeda dapat bermanfaat. Anda harus membuat kesalahan yang sama dalam dua teknologi yang berbeda agar tidak terdeteksi, dan itu tidak mungkin.

Di sisi lain, ada beberapa kelemahan juga. Testbenches berbasis Tcl adalah besaran lebih lambat dari rekan-rekan VHDL mereka. Masalah penting lainnya adalah penguncian vendor. Tidak mungkin membuat testbench Tcl yang sepenuhnya portabel, sedangkan testbench VHDL dapat berjalan di simulator apa pun yang mumpuni.

Dan alasan terakhir mengapa testbenches Tcl mungkin tidak sepadan adalah bahasa itu sendiri. Itu tidak memiliki fitur hebat untuk mencegah kesalahan pemrograman, dan men-debug masalah Tcl itu sulit. Ini bukan bahasa intuitif atau pemaaf seperti Python atau Java.

Namun, ini berfungsi sebagai bahasa perekat antara VHDL dan dunia perangkat lunak. Dan karena sebagian besar alat FPGA, tidak hanya simulator, mendukung Tcl, saya sangat menyarankan untuk mempelajarinya.

Pikiran-pikiran ini hanya pendapat saya. Ceritakan pendapatmu di kolom komentar!


VHDL

  1. Cara membuat daftar string di VHDL
  2. Bagaimana menghentikan simulasi di testbench VHDL
  3. Cara membuat pengontrol PWM di VHDL
  4. Cara membuat penyangga cincin FIFO di VHDL
  5. Testbench interaktif menggunakan Tcl
  6. Cara membuat testbench pemeriksaan mandiri
  7. Cara membuat Daftar Tertaut di VHDL
  8. Cara menggunakan Fungsi Tidak Murni di VHDL
  9. Cara menggunakan Fungsi di VHDL
  10. Cara memasang simulator dan editor VHDL secara gratis