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

Cara membuat daftar string di VHDL

String teks dalam VHDL umumnya terbatas pada array karakter dengan panjang tetap. Itu masuk akal karena VHDL menjelaskan perangkat keras, dan string dengan panjang generik memerlukan memori dinamis.

Untuk mendefinisikan array string, Anda harus mengalokasikan ruang pada waktu kompilasi untuk jumlah string tertinggi yang ingin Anda simpan. Dan lebih buruk lagi, Anda harus memutuskan panjang maksimal string dan pad setiap kemunculan jumlah karakter tersebut. Kode di bawah ini menunjukkan contoh penggunaan konstruksi semacam itu.

  type arr_type is array (0 to 3) of string(1 to 10);
  signal arr : arr_type;

begin

  arr(0) <= "Amsterdam ";
  arr(1) <= "Bangkok   ";
  arr(2) <= "Copenhagen";
  arr(3) <= "Damascus  ";

Sementara itu masuk akal dari perspektif perangkat keras, menjadi rumit untuk menggunakan array string di testbenches VHDL. Oleh karena itu, saya memutuskan untuk membuat paket daftar string dinamis yang akan saya jelaskan di artikel ini.

Anda dapat mengunduh kode lengkap menggunakan formulir di bawah ini.

Kelas daftar Python

Mari kita buat model daftar VHDL dinamis kita setelah implementasi daftar yang terkenal. Daftar string VHDL kami akan meniru perilaku kelas daftar bawaan Python. Kami akan mengadopsi append() , masukkan() , dan pop() metode dari daftar Python.

Untuk menunjukkan kepada Anda apa yang saya maksud, saya akan langsung masuk dan membuka shell python interaktif untuk menjalankan beberapa eksperimen.

Pertama, mari kita mulai dengan mendeklarasikan daftar dan menambahkan empat string ke dalamnya, seperti yang ditunjukkan di bawah ini.

IPython 7.19.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: l = []
In [2]: l.append("Amsterdam")
In [3]: l.append("Bangkok")
In [4]: l.append("Copenhagen")
In [5]: l.append("Damascus")

tambahkan() metodenya langsung; itu menambahkan objek ke akhir daftar.

Kami dapat memverifikasinya dengan pop() metode, yang menghapus elemen dan mengembalikannya ke pemanggil. Argumen menentukan posisi elemen yang akan diambil. Dengan memunculkan 0 hingga daftar kosong, kami mendapatkan konten yang diurutkan dari indeks terendah ke tertinggi:

In [6]: for _ in range(len(l)): print(l.pop(0))
Amsterdam
Bangkok
Copenhagen
Damascus

Oke, mari kita isi ulang daftarnya. Dan kali ini, kita akan menggunakan insert() metode untuk menambahkan elemen daftar rusak:

In [7]: l.insert(0, "Bangkok")
In [8]: l.insert(1, "Copenhagen")
In [9]: l.insert(0, "Amsterdam")
In [10]: l.insert(3, "Damascus")

insert() fungsi memungkinkan Anda menentukan di mana indeks untuk memasukkan item baru. Dalam contoh di atas, kami membuat daftar yang sama seperti sebelumnya. Mari kita periksa dengan melintasi daftar seperti array:

In [11]: for i in range(len(l)): print(l[i])
Amsterdam
Bangkok
Copenhagen
Damascus

Operator daftar kurung Python [] tidak menghapus item; itu membuat daftar berperilaku seperti array. Anda mendapatkan konten slot yang diindeks oleh nomor di dalam tanda kurung, seperti yang Anda lihat dari daftar di atas.

Mari kita kosongkan daftar dengan muncul, tapi kali ini dari akhir daftar. Keunikan daftar Python adalah Anda dapat menggunakan indeks negatif untuk menghitung dari item terakhir alih-alih dari awal daftar. Ia bekerja dengan operator braket dan dengan insert() atau pop() metode.

Dengan memunculkan indeks -1, Anda selalu mendapatkan item terakhir dari daftar. Saat kita memasukkannya ke dalam For loop, daftar akan dikosongkan dalam urutan terbalik:

In [12]: for _ in range(len(l)): print(l.pop(-1))
Damascus
Copenhagen
Bangkok
Amsterdam

Anda dapat menggunakan indeks negatif untuk menyisipkan juga. Pada baris terakhir dari contoh di bawah ini, kita memasukkan “Kopenhagen” pada indeks -1:

In [13]: l.append("Amsterdam")
In [14]: l.append("Bangkok")
In [15]: l.append("Damascus")
In [16]: l.insert(-1, "Copenhagen") # insert at the second last position

Saat kita menelusuri daftar, kita dapat melihat bahwa “Kopenhagen” sekarang menjadi elemen terakhir kedua:

In [17]: for i in range(len(l)): print(l[i])
Amsterdam
Bangkok
Copenhagen
Damascus

Sekarang, inilah intinya (tapi masuk akal).

Saat menyisipkan ke -1, item baru menjadi yang terakhir kedua, tetapi ketika muncul dari -1, kita mendapatkan item terakhir.

Masuk akal karena -1 mengacu pada posisi elemen terakhir saat ini dalam daftar. Dan ketika kami muncul, kami meminta elemen terakhir. Tetapi saat kami menyisipkan, kami meminta untuk memasukkan item baru di posisi elemen terakhir yang saat ini ada dalam daftar. Dengan demikian, item baru menggantikan elemen terakhir sebanyak satu slot.

Kami dapat mengonfirmasi ini dengan memunculkan elemen -1, yang mengembalikan “Damaskus”, dan bukan “Kopenhagen”:

In [18]: l.pop(-1) # pop from the last position
Out[18]: 'Damascus'

Daftar sekarang berisi tiga elemen:

In [19]: for i in range(len(l)): print(l[i])
Amsterdam
Bangkok
Copenhagen

Anda juga dapat menghitung panjang daftar seperti ini:

In [20]: len(l)
Out[20]: 3

Dan kita dapat mengosongkan daftar dengan memanggil clear() :

In [21]: l.clear()
In [22]: len(l)
Out[22]: 0

Seperti yang Anda lihat, daftar Python serbaguna, dan banyak programmer memahaminya. Itu sebabnya saya akan mendasarkan implementasi daftar VHDL saya pada formula sukses ini.

Prototipe subprogram VHDL daftar string

Untuk memungkinkan kita bekerja dengan daftar string seperti objek dengan metode anggota, kita harus mendeklarasikannya sebagai tipe yang dilindungi. Dan kami akan menempatkan jenis yang dilindungi dalam sebuah paket dengan nama yang sama:string_list .

Kode di bawah ini menunjukkan bagian "publik" dari tipe yang dilindungi yang mencantumkan prototipe subprogram.

package string_list is

  type string_list is protected

    procedure append(str : string);

    procedure insert(index : integer; str : string);

    impure function get(index : integer) return string;

    procedure delete(index : integer);

    procedure clear;

    impure function length return integer;

  end protected;

end package;

Sedangkan tambahkan() , masukkan() , dan clear() prosedur identik dengan rekan Python mereka, kami tidak dapat mem-port pop() berfungsi langsung ke VHDL. Masalahnya adalah kita tidak dapat dengan mudah melewatkan objek dinamis dari tipe yang dilindungi di VHDL.

Untuk mengatasi batasan ini, saya telah membagi pop() fungsionalitas menjadi dua subprogram:get() dan hapus() . Itu akan memungkinkan kita untuk mengindeks elemen terlebih dahulu, seperti array, dan kemudian menghapusnya saat kita tidak membutuhkannya lagi. Misalnya, setelah kita mencetak string ke konsol simulator.

panjang() fungsi tidak murni akan berperilaku seperti len() bawaan Python fungsi. Ini akan mengembalikan jumlah string dalam daftar.

Implementasi VHDL daftar string

Jenis yang dilindungi terdiri dari dua bagian:bagian deklaratif dan badan. Sementara bagian deklaratif terlihat oleh pengguna, badan berisi implementasi subprogram dan variabel pribadi apa pun. Sekarang saatnya untuk mengungkapkan cara kerja bagian dalam dari daftar string.

Tinggalkan alamat email Anda di formulir di bawah ini untuk menerima kode lengkap dan proyek ModelSim di kotak masuk Anda!

Kami akan menggunakan daftar tertaut tunggal sebagai struktur data internal.

Baca juga:Cara membuat Linked List di VHDL

Karena semua kode yang mengikuti ada di badan tipe yang dilindungi, konstruksi ini tidak dapat diakses secara langsung di luar paket ini. Semua komunikasi harus melalui subprogram yang terdaftar di wilayah deklaratif yang telah kita bahas di bagian sebelumnya.

Jenis dan variabel penyimpanan data

Seperti yang Anda lihat dari kode di bawah ini, pertama-tama kita mendeklarasikan tipe akses, penunjuk VHDL ke string dalam memori dinamis. Ketika kita berbicara tentang memori dinamis, itu bukan DRAM pada FPGA karena kode ini tidak dapat disintesis. Daftar string adalah murni komponen simulasi, dan akan menggunakan memori dinamis dari komputer yang menjalankan simulasi.

type str_ptr is access string;
type item;
type item_ptr is access item;
type item is record
  str : str_ptr;
  next_item : item_ptr;
end record;

Setelah str_ptr , kami mendeklarasikan item sebagai tipe yang tidak lengkap. Kita harus melakukannya seperti itu karena pada baris berikutnya, kita mereferensikan item saat membuat item_ptr .

Dan akhirnya, kami menentukan deklarasi lengkap dari item type, record yang berisi pointer string dan pointer ke elemen berikutnya. Ada ketergantungan melingkar antara jenis item->item_ptr->item , dan dengan terlebih dahulu mendeklarasikan item yang tidak lengkap ketik, kami menghindari kesalahan kompilasi.

Jenis yang dilindungi berisi dua variabel, yang ditunjukkan di bawah ini:root dan length_i . Item yang ditunjuk oleh root akan menjadi elemen pertama dari daftar, indeks array nol. Dan length_i variabel akan selalu mencerminkan jumlah string dalam daftar.

variable root : item_ptr;
variable length_i : integer := 0;

Tambahkan prosedur

tambahkan() prosedur yang ditunjukkan di bawah ini adalah notasi singkat untuk menyisipkan string pada posisi terakhir daftar.

procedure append(str : string) is
begin
  insert(length_i, str);
end procedure;

Seperti yang dibahas dalam contoh Python, mudah untuk menyisipkan di posisi kedua terakhir menggunakan indeks -1:insert(-1, str) . Tetapi memasukkan pada posisi terakhir membutuhkan panjang daftar sebagai argumen indeks. Itu mungkin mengapa daftar Python memiliki append() khusus metode, dan kami juga akan memilikinya.

Memasukkan prosedur

Prosedur penyisipan, yang ditunjukkan di bawah, bekerja dalam empat langkah.

Pertama, kita membuat objek item dinamis dengan menggunakan VHDL new kata kunci. Pertama-tama kita membuat objek item daftar dan kemudian objek string dinamis untuk disimpan di dalamnya.

procedure insert(index : integer; str : string) is
  variable new_item : item_ptr;
  variable node : item_ptr;
  variable index_v : integer;
begin

  -- Create the new object
  new_item := new item;
  new_item.str := new string'(str);

  -- Restrict the index to the list range
  if index >= length_i then
    index_v := length_i;
  elsif index <= -length_i then
    index_v := 0;
  else
    index_v := index mod length_i;
  end if;

  if index_v = 0 then

    -- The new object becomes root when inserting at position 0
    new_item.next_item := root;
    root := new_item;

  else

    -- Find the node to insert after
    node := root;
    for i in 2 to index_v loop
      node := node.next_item;
    end loop;

    -- Insert the new item
    new_item.next_item := node.next_item;
    node.next_item := new_item;

  end if;

  length_i := length_i + 1;

end procedure;

Langkah nomor dua adalah menerjemahkan argumen indeks ke indeks yang sesuai dengan rentang daftar. list.insert() dari Python implementasi memungkinkan indeks di luar batas, dan daftar VHDL kami juga akan mengizinkannya. Jika pengguna mereferensikan indeks yang terlalu tinggi atau rendah, itu akan default ke indeks tertinggi, atau elemen 0. Selain itu, kami menggunakan operator modulo untuk menerjemahkan indeks negatif masuk ke posisi array positif.

Pada langkah nomor tiga, kita menelusuri daftar untuk menemukan simpul yang akan disisipkan setelahnya. Seperti biasa, dengan linked list, kita harus secara eksplisit menangani kasus penyisipan tertentu di root.

Langkah keempat dan terakhir adalah menambah length_i variabel untuk memastikan pembukuan mutakhir.

Fungsi get_index dan get_node internal

Karena keterbatasan lewat objek VHDL, kami memutuskan untuk membagi pop() menjadi dua subprogram:get() dan hapus() . Fungsi pertama akan mendapatkan item, dan prosedur kedua akan menghapusnya dari daftar.

Tetapi algoritme untuk mencari indeks atau objek identik untuk get() dan hapus() , sehingga kita dapat mengimplementasikannya secara terpisah dalam dua fungsi pribadi:get_index() dan get_node() .

Tidak seperti insert() , pop() Python Python fungsi tidak mengizinkan indeks di luar batas, dan juga get_index() . kami fungsi. Untuk menjaga dari kesalahan pengguna, kami akan memunculkan pernyataan kegagalan jika indeks yang diminta di luar batas, seperti yang ditunjukkan di bawah ini.

impure function get_index(index : integer) return integer is
begin
  assert index >= -length_i and index < length_i
    report "get index out of list range"
    severity failure;

  return index mod length_i;
end function;

get_node() fungsi, yang ditunjukkan di bawah, mengambil langkah lebih jauh dan menemukan objek sebenarnya pada indeks yang ditentukan. Ini menggunakan get_index() untuk mencari node yang benar dan mengembalikan pointer ke item objek.

impure function get_node(index : integer) return item_ptr is
  variable node : item_ptr;
begin

  node := root;
  for i in 1 to get_index(index) loop
    node := node.next_item;
  end loop;

  return node;

end function;

Dapatkan fungsi

Karena get_node() private pribadi fungsi, get() public publik fungsi menjadi agak sederhana. Ini adalah one-liner yang mengambil node yang benar, membongkar konten string, dan mengembalikannya ke pemanggil.

impure function get(index : integer) return string is
begin
  return get_node(index).str.all;
end function;

Prosedur penghapusan

hapus() prosedur juga menggunakan get_index() dan get_node() untuk menyederhanakan algoritma. Pertama, kita menggunakan get_index() untuk menemukan indeks objek yang akan dihapus, seperti yang ditunjukkan dalam index_c deklarasi konstan di bawah ini.

procedure delete(index : integer) is
  constant index_c : integer := get_index(index);
  variable node : item_ptr;
  variable parent_node : item_ptr;
begin

  if index_c = 0 then
    node := root;
    root := root.next_item;
  else
    parent_node := get_node(index_c - 1);
    node := parent_node.next_item;
    parent_node.next_item := node.next_item;
  end if;

  deallocate(node.str);
  deallocate(node);

  length_i := length_i - 1;

end procedure;

Kemudian, kami memutuskan tautan simpul dari daftar. Jika itu adalah objek root, kami menetapkan item berikutnya sebagai root. Jika tidak, kami menggunakan get_node() untuk menemukan induk dan menautkan kembali daftar untuk melepaskan item yang ada.

Dan terakhir, kita mengosongkan memori dengan memanggil kata kunci VHDL deallocate dan perbarui length_i variabel pembukuan.

Prosedur yang jelas

Untuk menghapus semua item, tombol clear() prosedur melintasi daftar menggunakan loop While, memanggil delete() pada setiap elemen sampai tidak ada yang tersisa.

procedure clear is
begin
  while length_i > 0 loop
    delete(0);
  end loop;
end procedure;

Fungsi panjang

Untuk mematuhi praktik pemrograman yang baik, kami menyediakan fungsi pengambil alih-alih mengizinkan pengguna untuk langsung mengakses length_i variabel.

impure function length return integer is
begin
  return length_i;
end function;

Perbedaannya tidak terlalu mencolok bagi pengguna karena Anda tidak memerlukan tanda kurung untuk memanggil fungsi tanpa parameter (my_list.length ). Tetapi pengguna tidak dapat mengubah variabel pembukuan internal, dan itu adalah perlindungan terhadap penyalahgunaan.

Menggunakan daftar string di testbench

Setelah implementasi list selesai, saatnya kita menjalankannya di testbench. Pertama, kita harus mengimpor jenis yang dilindungi dari sebuah paket, seperti yang ditunjukkan pada baris pertama kode di bawah ini.

use work.string_list.string_list;

entity string_list_tb is
end string_list_tb;

architecture sim of string_list_tb is

  shared variable l : string_list;
...

Jenis yang dilindungi adalah konstruksi seperti kelas VHDL, dan kita dapat membuat objeknya dengan mendeklarasikan variabel bersama bertipe string_list , seperti yang ditunjukkan pada baris terakhir di atas. Kami akan menamakannya 'l' untuk "daftar" untuk mereplikasi contoh Python yang saya sajikan di awal artikel ini.

Mulai sekarang, kita dapat menggunakan pendekatan perangkat lunak untuk mengakses data daftar. Seperti yang ditunjukkan pada proses testbench di bawah ini, kita dapat mereferensikan subprogram publik dengan menggunakan notasi titik pada variabel bersama (l.append("Amsterdam") ).

begin
  SEQUENCER_PROC : process
  begin

    print("* Append four strings");
    print("  l.append(Amsterdam)"); l.append("Amsterdam");
    print("  l.append(Bangkok)"); l.append("Bangkok");
    print("  l.append(Copenhagen)"); l.append("Copenhagen");
    print("  l.append(Damascus)"); l.append("Damascus");
...

Saya telah menghilangkan testbench lengkap dan menjalankan skrip untuk mengurangi panjang artikel ini, tetapi Anda dapat memintanya dengan meninggalkan alamat email Anda di formulir di bawah ini. Anda akan menerima file Zip dengan kode VHDL lengkap dan proyek ModelSim di kotak masuk Anda dalam beberapa menit.

Menjalankan testbench

Jika Anda mengunduh proyek contoh menggunakan formulir di atas, Anda seharusnya dapat mereplikasi output berikut. Lihat “Cara menjalankan.txt” di file Zip untuk instruksi yang tepat.

Ini adalah testbench pemeriksaan manual, dan saya telah membuat test case menyerupai contoh Python saya sedekat mungkin. Alih-alih pop() Metode Python, kami menggunakan get() list daftar VHDL fungsi diikuti dengan panggilan ke delete() . Itu melakukan hal yang sama.

Seperti yang dapat kita lihat dari cetakan ke konsol ModelSim yang ditunjukkan di bawah, daftar VHDL berperilaku serupa dengan rekan Python-nya.

# * Append four strings
#   l.append(Amsterdam)
#   l.append(Bangkok)
#   l.append(Copenhagen)
#   l.append(Damascus)
# * Pop all strings from the beginning of the list
#   l.get(0): Amsterdam
#   l.get(1): Bangkok
#   l.get(2): Copenhagen
#   l.get(3): Damascus
# * Insert four strings in shuffled order
#   l.insert(0, Bangkok)
#   l.insert(1, Copenhagen)
#   l.insert(0, Amsterdam)
#   l.insert(3, Damascus)
# * Traverse the list like an array
#   l.get(0): Amsterdam
#   l.get(1): Bangkok
#   l.get(2): Copenhagen
#   l.get(3): Damascus
# * Pop all strings from the end of the list
#   l.get(0): Damascus
#   l.get(1): Copenhagen
#   l.get(2): Bangkok
#   l.get(3): Amsterdam
# * Append and insert at the second last position
#   l.append(Amsterdam)
#   l.append(Bangkok)
#   l.append(Damascus)
#   l.insert(-1, Copenhagen)
# * Pop from the last position
#   l.get(-1): Damascus
# * Traverse the list like an array
#   l.get(0): Amsterdam
#   l.get(1): Bangkok
#   l.get(2): Copenhagen
# * Check the list length
#   l.length: 3
# * Clear the list
# * Check the list length
#   l.length: 0
# * Done

Pemikiran terakhir

Saya pikir fitur pemrograman tingkat tinggi dari VHDL diremehkan. Meskipun tidak berguna untuk desain RTL karena tidak dapat disintesis, ini dapat bermanfaat untuk tujuan verifikasi.

Meskipun mungkin rumit untuk diimplementasikan, akan lebih mudah bagi pengguna akhir, orang yang menulis testbench yang menggunakan tipe yang dilindungi. Jenis yang dilindungi menyembunyikan semua kerumitan dari pengguna.

Hanya membutuhkan tiga baris untuk menggunakan tipe yang dilindungi:mengimpor paket, mendeklarasikan variabel bersama, dan memanggil subprogram dalam proses testbench. Itu lebih sederhana daripada membuat instance komponen VHDL.

Lihat juga:Cara membuat Daftar Tertaut di VHDL

Beri tahu saya pendapat Anda di bagian komentar di bawah artikel!


VHDL

  1. Cara membuat testbench berbasis Tcl untuk modul kunci kode VHDL
  2. Bagaimana menghentikan simulasi di testbench VHDL
  3. Cara membuat pengontrol PWM di VHDL
  4. Cara menghasilkan angka acak di VHDL
  5. Cara membuat penyangga cincin FIFO di VHDL
  6. Cara membuat testbench pemeriksaan mandiri
  7. Cara membuat Daftar Tertaut di VHDL
  8. Cara menggunakan Prosedur dalam Proses di VHDL
  9. Cara menggunakan Fungsi Tidak Murni di VHDL
  10. Cara menggunakan Fungsi di VHDL