Cara menginisialisasi RAM dari file menggunakan TEXTIO
Cara mudah untuk mengisi blok RAM dengan nilai awal adalah dengan membaca literal biner atau heksadesimal dari file ASCII. Ini juga merupakan cara yang baik untuk membuat ROM (memori hanya-baca) di VHDL. Bagaimanapun, RAM dan ROM adalah hal yang sama di FPGA, ROM adalah RAM yang hanya Anda baca.
Contoh di seluruh artikel ini akan mengasumsikan bahwa konstanta dan tipe RAM berikut telah dideklarasikan di awal wilayah deklaratif file VHDL.
constant ram_depth : natural := 256;
constant ram_width : natural := 32;
type ram_type is array (0 to ram_depth - 1)
of std_logic_vector(ram_width - 1 downto 0);
Posting blog ini adalah bagian dari seri tentang penggunaan perpustakaan TEXTIO di VHDL. Baca artikel lainnya di sini:
File stimulus dibaca di testbench menggunakan TEXTIO
Gambar bitmap file BMP dibaca menggunakan TEXTIO
BACA, GARIS, HREAD, OREAD, dan ROTI
Subprogram dan jenis yang diperlukan untuk membaca dan menulis file eksternal di VHDL terletak di TEXTIO
kemasan. Paket ini adalah bagian dari std
Perpustakaan. Pustaka standar selalu dimuat; oleh karena itu, kita tidak perlu mengimpornya secara eksplisit dengan kode library
kata kunci.
Kita bisa melanjutkan dan menggunakan TEXTIO
package di header file VHDL kita seperti ini:
use std.textio.all;
Kami akan menyimpan data RAM dalam file ASCII di mana satu baris teks sesuai dengan slot memori. Untuk membaca sebaris teks kita menggunakan READLINE
prosedur dari TEXTIO
kemasan. Prosedur ini membutuhkan dua argumen, nama file sebagai input konstan dan baris teks yang diurai sebagai inout
variabel. Deklarasi prototipe READLINE
prosedur dan LINE
jenis yang diambil dari spesifikasi standar VHDL ditunjukkan di bawah ini.
procedure READLINE (file F: TEXT; L: inout LINE);
type LINE is access STRING; -- A LINE is a pointer
-- to a STRING value.
Meskipun kelas LINE
parameter tidak secara eksplisit ditentukan dalam deklarasi prototipe READLINE
, ini adalah variabel karena itu adalah kelas default untuk inout
parameter. LINE
type hanyalah tipe akses ke string, pointer ke objek string yang dialokasikan secara dinamis.
VHDL-2008 mendefinisikan OREAD
, HREAD
, dan BREAD
prosedur untuk mengekstrak nilai oktal, heksadesimal, dan biner dari LINE
obyek. Metode untuk membaca nilai oktal dan heksadesimal sangat mirip, nilai oktal hanyalah bagian dari heksadesimal. Untuk mempermudah, kita akan melewatkan pembacaan oktal dalam artikel ini dan fokus pada cara membaca nilai heksadesimal dan biner dari file teks.
Kode di bawah ini menunjukkan definisi prosedur yang relevan bagi kami, mereka hanya tersedia di VHDL-2008 dan revisi yang lebih baru. OREAD
dan HREAD
prosedur datang dalam dua rasa kelebihan beban untuk masing-masing jenis output yang didukung. GOOD
opsional output dapat digunakan untuk mendeteksi kesalahan baca, meskipun, sebagian besar alat akan menghasilkan kesalahan atau peringatan terlepas dari apakah output ini digunakan atau tidak.
procedure OREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR;
GOOD : out BOOLEAN);
procedure OREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR);
procedure HREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR;
GOOD : out BOOLEAN);
procedure HREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR);
alias BREAD is READ [LINE, STD_ULOGIC_VECTOR, BOOLEAN];
alias BREAD is READ [LINE, STD_ULOGIC_VECTOR];
Klik di sini untuk melihat definisi prosedur input dari perpustakaan TEXTIO
procedure READLINE (file F: TEXT; L: inout LINE);
procedure READ (L: inout LINE; VALUE: out BIT;
GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out BIT);
procedure READ (L: inout LINE; VALUE: out BIT_VECTOR;
GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out BIT_VECTOR);
procedure READ (L: inout LINE; VALUE: out BOOLEAN;
GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out CHARACTER;
GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out CHARACTER);
procedure READ (L: inout LINE; VALUE: out INTEGER;
GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out INTEGER);
procedure READ (L: inout LINE; VALUE: out REAL;
GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out REAL);
procedure READ (L: inout LINE; VALUE: out STRING;
GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out STRING);
procedure READ (L: inout LINE; VALUE: out TIME;
GOOD: out BOOLEAN);
procedure READ (L: inout LINE; VALUE: out TIME);
procedure SREAD (L: inout LINE; VALUE: out STRING;
STRLEN: out NATURAL);
alias STRING_READ is SREAD [LINE, STRING, NATURAL];
alias BREAD is READ [LINE, BIT_VECTOR, BOOLEAN];
alias BREAD is READ [LINE, BIT_VECTOR];
alias BINARY_READ is READ [LINE, BIT_VECTOR, BOOLEAN];
alias BINARY_READ is READ [LINE, BIT_VECTOR];
procedure OREAD (L: inout LINE; VALUE: out BIT_VECTOR;
GOOD: out BOOLEAN);
procedure OREAD (L: inout LINE; VALUE: out BIT_VECTOR);
alias OCTAL_READ is OREAD [LINE, BIT_VECTOR, BOOLEAN];
alias OCTAL_READ is OREAD [LINE, BIT_VECTOR];
procedure HREAD (L: inout LINE; VALUE: out BIT_VECTOR;
GOOD: out BOOLEAN);
procedure HREAD (L: inout LINE; VALUE: out BIT_VECTOR);
alias HEX_READ is HREAD [LINE, BIT_VECTOR, BOOLEAN];
alias HEX_READ is HREAD [LINE, BIT_VECTOR];
Klik di sini untuk melihat definisi prosedur input dari perpustakaan std_logic_1164
procedure READ (L : inout LINE; VALUE : out STD_ULOGIC; GOOD : out BOOLEAN);
procedure READ (L : inout LINE; VALUE : out STD_ULOGIC);
procedure READ (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR; GOOD : out BOOLEAN);
procedure READ (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR);
alias BREAD is READ [LINE, STD_ULOGIC_VECTOR, BOOLEAN];
alias BREAD is READ [LINE, STD_ULOGIC_VECTOR];
alias BINARY_READ is READ [LINE, STD_ULOGIC_VECTOR, BOOLEAN];
alias BINARY_READ is READ [LINE, STD_ULOGIC_VECTOR];
procedure OREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR; GOOD : out BOOLEAN);
procedure OREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR);
alias OCTAL_READ is OREAD [LINE, STD_ULOGIC_VECTOR, BOOLEAN];
alias OCTAL_READ is OREAD [LINE, STD_ULOGIC_VECTOR];
procedure HREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR; GOOD : out BOOLEAN);
procedure HREAD (L : inout LINE; VALUE : out STD_ULOGIC_VECTOR);
alias HEX_READ is HREAD [LINE, STD_ULOGIC_VECTOR, BOOLEAN];
alias HEX_READ is HREAD [LINE, STD_ULOGIC_VECTOR];
Baca nilai hex dari file
Heksadesimal adalah format yang berguna untuk menggambarkan konten RAM karena dua karakter hex langsung diterjemahkan menjadi satu byte, delapan bit. Setiap karakter menggambarkan nibble (setengah byte) dan setiap baris dalam file teks menggambarkan isi dari satu slot RAM. Daftar di bawah ini menunjukkan kutipan dari ram_content_hex.txt mengajukan. Itu sudah diisi dengan contoh nilai mulai dari 1 sampai 256 desimal, ditulis sebagai hex.
12–255256 | 00000001 00000002 ... 000000FF 00000100 |
Untuk memuat data dari file teks, kami menggunakan fungsi tidak murni yang dideklarasikan di bawah ram_type
, tetapi di atas deklarasi sinyal RAM. Kode di bawah ini menunjukkan init_ram_hex
fungsi yang membaca data dari file teks dan mengembalikannya sebagai ram_type
objek.
impure function init_ram_hex return ram_type is
file text_file : text open read_mode is "ram_content_hex.txt";
variable text_line : line;
variable ram_content : ram_type;
begin
for i in 0 to ram_depth - 1 loop
readline(text_file, text_line);
hread(text_line, ram_content(i));
end loop;
return ram_content;
end function;
readline
prosedur di dalam for-loop membaca satu baris teks pada saat itu dan menetapkannya ke text_line
variabel. Objek ini bertipe line
, yang merupakan tipe akses ke objek string, penunjuk ke string yang dialokasikan secara dinamis. Pada baris berikutnya, hread
prosedur membaca string dari line
objek dan mengubahnya menjadi std_ulogic_vector
. Jenis ini dapat ditetapkan langsung ke std_logic_vector
dari mana setiap sel RAM dibuat.
Terakhir, kami mendeklarasikan sinyal RAM saat memanggil init_ram_hex
berfungsi untuk memberikan nilai awal untuknya:
signal ram_hex : ram_type := init_ram_hex;
HREAD dalam VHDL-2002 dan VHDL-93
Sayangnya, HREAD
prosedur ini hanya tersedia di VHDL-2008. Di semua versi VHDL sebelumnya, standar READ
prosedur harus digunakan sebagai gantinya. READ
prosedur kelebihan beban dengan banyak jenis keluaran yang berbeda, tetapi tidak ada opsi untuk membaca nilai heksadesimal.
Mari kita menulis algoritme khusus untuk mengonversi karakter ASCII heksadesimal ke std_logic_vector
VHDL . Pertama, kita perlu membaca karakter satu per satu dari text_line
objek, lalu kami mendekode nilainya dan menetapkannya ke irisan yang benar dari vektor slot RAM. Kode di bawah ini menunjukkan implementasi yang setara dari init_ram_hex
fungsi yang juga berfungsi di versi VHDL lawas.
impure function init_ram_hex return ram_type is
file text_file : text open read_mode is "ram_content_hex.txt";
variable text_line : line;
variable ram_content : ram_type;
variable c : character;
variable offset : integer;
variable hex_val : std_logic_vector(3 downto 0);
begin
for i in 0 to ram_depth - 1 loop
readline(text_file, text_line);
offset := 0;
while offset < ram_content(i)'high loop
read(text_line, c);
case c is
when '0' => hex_val := "0000";
when '1' => hex_val := "0001";
when '2' => hex_val := "0010";
when '3' => hex_val := "0011";
when '4' => hex_val := "0100";
when '5' => hex_val := "0101";
when '6' => hex_val := "0110";
when '7' => hex_val := "0111";
when '8' => hex_val := "1000";
when '9' => hex_val := "1001";
when 'A' | 'a' => hex_val := "1010";
when 'B' | 'b' => hex_val := "1011";
when 'C' | 'c' => hex_val := "1100";
when 'D' | 'd' => hex_val := "1101";
when 'E' | 'e' => hex_val := "1110";
when 'F' | 'f' => hex_val := "1111";
when others =>
hex_val := "XXXX";
assert false report "Found non-hex character '" & c & "'";
end case;
ram_content(i)(ram_content(i)'high - offset
downto ram_content(i)'high - offset - 3) := hex_val;
offset := offset + 4;
end loop;
end loop;
return ram_content;
end function;
Algoritma hanya melewati setiap baris sambil melihat setiap karakter, mengubahnya menjadi nilai biner yang benar. Jika karakter yang tidak berada dalam rentang 0x0-0xF ditemukan, kegagalan penegasan akan muncul di when others
cabang. offset
variabel mengontrol posisi irisan dalam setiap sel memori untuk menetapkan nilai yang didekodekan.
Anda mungkin bertanya pada diri sendiri mengapa kami tidak membuat hread
khusus prosedur alih-alih mengkodekannya di dalam init_ram_hex
fungsi? Maka kita tidak perlu mengubah init_ram_hex
fungsi sama sekali, kami hanya akan menggunakan hread
khusus kami menggantikan prosedur standar yang hilang.
Itu akan bekerja di sebagian besar simulator dan beberapa synthesizer seperti Lattice iCEcube2, tetapi tidak akan disintesis di Xilinx Vivado. Pesan kesalahan di bawah ini dengan jelas menyatakan apa masalahnya.
Di Vivado:
[Synth 8-27] Argumen prosedur tipe 'baris' tidak didukung [init_ram_tb.vhd:15]
Klik di sini untuk melihat implementasi alternatif dari prosedur HREAD
procedure hread(l: inout line; value: out std_logic_vector) is
variable c : character;
variable ok : boolean;
variable i : integer := 0;
variable hex_val : std_logic_vector(3 downto 0);
begin
while i < value'high loop
read(l, c);
case c is
when '0' => hex_val := "0000";
when '1' => hex_val := "0001";
when '2' => hex_val := "0010";
when '3' => hex_val := "0011";
when '4' => hex_val := "0100";
when '5' => hex_val := "0101";
when '6' => hex_val := "0110";
when '7' => hex_val := "0111";
when '8' => hex_val := "1000";
when '9' => hex_val := "1001";
when 'A' | 'a' => hex_val := "1010";
when 'B' | 'b' => hex_val := "1011";
when 'C' | 'c' => hex_val := "1100";
when 'D' | 'd' => hex_val := "1101";
when 'E' | 'e' => hex_val := "1110";
when 'F' | 'f' => hex_val := "1111";
when others =>
hex_val := "XXXX";
assert false report "Found non-hex character '" & c & "'";
end case;
value(value'high - i downto value'high - i - 3) := hex_val;
i := i + 4;
end loop;
end procedure;
Baca nilai biner dari file
Anda mungkin ingin menyimpan nilai RAM sebagai literal biner alih-alih karakter hex jika lebar RAM bukan kelipatan 8. Daftar di bawah ini menunjukkan konten yang sama seperti sebelumnya, tetapi diwakili dalam format biner hanya menggunakan karakter 0
dan 1
.
12–255256 | 00000000000000000000000000000001 00000000000000000000000000000010 ... 00000000000000000000000011111111 00000000000000000000000100000000 |
Algoritma yang ditunjukkan di bawah ini adalah untuk membaca nilai biner dari file. Ini mirip dengan membaca heksadesimal, tetapi dalam VHDL-2008 Anda harus menggunakan BREAD
panggilan prosedur alih-alih HREAD
. Ini akan menerjemahkan satu karakter ASCII menjadi satu std_ulogic
nilai, yang secara implisit dikonversi ke std_logic
.
impure function init_ram_bin return ram_type is
file text_file : text open read_mode is "ram_content_bin.txt";
variable text_line : line;
variable ram_content : ram_type;
begin
for i in 0 to ram_depth - 1 loop
readline(text_file, text_line);
bread(text_line, ram_content(i));
end loop;
return ram_content;
end function;
Terakhir, kita menginisialisasi sinyal RAM dengan memanggil fungsi baru kita yang tidak murni seperti yang ditunjukkan pada kode di bawah ini.
signal ram_bin : ram_type := init_ram_bin;
ROTI dalam VHDL-2002 dan VHDL-93
Kami dapat dengan mudah membuat kode kami portabel ke versi VHDL lama dengan memanggil READ
bukannya BREAD
. Kutipan dari standar VHDL di bawah ini menunjukkan prototipe READ
yang ingin kami gunakan.
procedure READ (L: inout LINE; VALUE: out BIT);
READ
prosedur yang menghasilkan std_ulogic
tidak ada sebelum VHDL-2008, oleh karena itu kita harus menggunakan bit
versi dari TEXTIO
Perpustakaan. Untungnya, tipe ini dapat dengan mudah diubah menjadi std_logic
dengan menggunakan To_StdLogicVector
standar fungsi.
Implementasi init_ram_bin
yang ditunjukkan di bawah ini berfungsi di VHDL-2002 dan juga di VHDL-93.
impure function init_ram_bin return ram_type is
file text_file : text open read_mode is "ram_content_bin.txt";
variable text_line : line;
variable ram_content : ram_type;
variable bv : bit_vector(ram_content(0)'range);
begin
for i in 0 to ram_depth - 1 loop
readline(text_file, text_line);
read(text_line, bv);
ram_content(i) := To_StdLogicVector(bv);
end loop;
return ram_content;
end function;
Backport perpustakaan IEEE std_logic_1164
Alternatif untuk mengubah kode untuk versi VHDL lawas adalah dengan menggunakan paket pihak ketiga std_logic_1164_additions. Dengan mengunduh dan menambahkan pustaka ini ke proyek Anda, Anda akan dapat menggunakan prosedur baru juga di VHDL-2002 dan VHDL-93. Tentu saja, Anda akan mengimpor lebih banyak dan kode Anda akan selalu bergantung pada paket ini.