courses:system_design:simulation:file_io

File I/O

Structure of a design

Structure of a design

  • Which files will have to be recompiled if there is a change in the following files? (only minor changes, i.e. comments)
  • Entity of module C
  • Architecture of module D
  • Package PKG1
  • Package PKG2
  • Package body PKG2
  • Architecture of TB
  • Configuration of TB

Notes

The design DUT which is to be simulated consists of several modules (A,B,C,D). The packages PKG1 and PKG2 are referenced in module A and B, respectively. The package PKG1 is split into the package header containing declarations of subprograms, data types and constants and a package body with the corresponding definitions.

The following order is suitable for the initial compilation: PKG1, PKG2, body of PKG2, module D, C, B, A, DUT, TB (entity first) and finally the testbench configuration. As the configuration creates the simulatable object, is has to recompiled whenever something is changed.

If entity C is changed, the corresponding architecture and the configuation have to be recompiled. A modification of D’s architecture does not require any additional recompilations apart from the configuration. A recompilation of PKG1 leads to recompilations of the complete module A and the configuration.

Changes in PKG2 imply that the package body and module B have to be recompiled. If the changes are restricted to the package body, only the configuration, as always, remains to be updated. The same applies to modified testbench (TB) architectures and changes to the configuration itself.

Please note, that only minor modifications, e.g. in the VHDL comments where considered here. If entity ports are changed, for example, a simple recompilation is not enough and the VHDL code of the modules on all hierarchy levels might have to be adjusted accordingly. The interface mismatch is detected when compiling the configuration.

File I/O

  • Package TEXTIO of STD library
  • Important functions and procedures:
    • readline(…), read(…),
    • writeline(…), write(…),
    • endfile(…)
  • Additional data types (text, line)
  • READ / WRITE overloaded for all predefined data types:
    • bit, bit_vector
    • boolean
    • character, string
    • integer, real
    • time

Notes

In VHDL, the designer is allowed to load data from or save data to a file. To do this, it is necessary to include the TEXTIO package of the STD library which contains basic functions and procedures.

These subprograms (write, writeline, read, readline, …) facilitate the file I/O mechanism and are defined for the predefined VHDL data types. The main application of file I/O is simulation flexibility. This means that simulation stimuli and response analysis are left to specialized software, which is often easier than writing the corresponding VHDL models.

To get the information from a file, the user reads it line by line (READLINE procedure) and stores the data in a variable of the data type ’line’. Afterwards it is possible to access the data from this line with the READ command. Usually a line contains information of different data types.

To interpret the data in a correct way, i.e. a string as a string and an integer value as an integer, you have to employ actual parameters of the same data type. This fact will become clearer in the following example.

Besides it is necessary to read the space character between the information in a separate read statement!

The file output works in a similar way, i.e. a line is assembled first via WRITE commands and is finally written to the file with a WRITELINE statement.

Adder block diagram example

  • ADDER module
    • Adds two 8 bit vectors and provides an 8 bit result vector
    • Generates an overflow signal
  • Entity and architecture of the ADDER module
  • std_logic_unsigned package
    • Copyright by Synopsys (EDA software company)
    • Not standardized by IEEE
    • Overloaded mathematical operators where std_logic_vector is treated as unsigned number
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
entity ADDER is
port(VALUE_1: in std_logic_vector(7 downto 0);
     VALUE_2: in std_logic_vector(7 downto 0);
     OVERFLOW: out std_logic;
     RESULT: out std_logic_vector(7 downto 0)
     );
end ADDER;
architecture RTL of ADDER is
 signal INT_RES: std_logic_vector(8 downto 0);
 signal INT_VAL_1: std_logic_vector(8 downto 0);
 signal INT_VAL_2: std_logic_vector(8 downto 0);
begin
  INT_VAL_1 <=0& VALUE_1;
  INT_VAL_2 <=0& VALUE_2;
  INT_RES <= INT_VAL_1 + INT_VAL_2;
  RESULT <= INT_RES(7 downto 0);
  OVERFLOW <= INT_RES(8);
end RTL;

Notes

The first part of the file I/O example shows a design of an adder (entity and architecture). Please note the use of the STD_LOGIC_UNSIGNED package. Although this package is located in the IEEE library it is not standardized by the institute. The package was created by Synopsys Inc., an EDA software company.

Their packages, however, have achieved the level of a quasi-standard in industry.

In the architecture, the operands are extended to 9 bits in order to avoid an overflow during the actual addition. The most significant bit of the resulting vector is then used as OVERFLOW signal and the lower 8 bits represent the result of the addition.

  • Add package std.textio; IEEE.std_logic_textio for file I/O functions and procedures
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_textio.all;
use STD.textio.all;
  • Common testbench structure
    • Empty entity; no external interface
    • Component declaration and instantiation
    • Definition of internal signals to connect the input/output ports with the stimuli/response analysis processes
entity TB_ADDER is
end TB_ADDER;
 
architecture BEH of TB_ADDER is
 component ADDER
  port(VALUE_1  : in std_logic_vector(7 downto 0);
       VALUE_2  : in std_logic_vector(7 downto 0);
       OVERFLOW : out std_logic;
       RESULT   : out std_logic_vector(7 downto 0));
end component;
 
  signal W_VALUE_1  : std_logic_vector(7 downto 0);
  signal W_VALUE_2  : std_logic_vector(7 downto 0);
  signal W_OVERFLOW : std_logic;
  signal W_RESULT   : std_logic_vector(7 downto 0);
 
begin
 DUT : ADDER
  port map(VALUE_1  => W_VALUE_1,
           VALUE_2  => W_VALUE_2,
           OVERFLOW => W_OVERFLOW,
           RESULT   => W_RESULT);

Notes

The testbench for the ADDER design follows the usual structure.

The entity remains empty as no higher hierarchy level exists and in the declarative part of the architecture the design under test and signals for its interface ports are declared. In the component instantiation statement, these signals are connected to the DUT ports.

Please note that two additional packages are used to handle the file I/O.

  • The standard TEXTIO package provides the basic functionality.
  • The STD_LOGIC_TEXTIO, again a Synopsys package that is not standardized by the IEEE, provides overloaded subprograms to handle ’std_ulogic’ based data types.
  • STIMULI process
    • File access is limited to only one line at a certain time
    • Only variables are allowed for the parameters of the read functions
    • The function hread(…) is defined in the IEEE.std_logic_textio package; it reads hex values and transforms them into a binary vector
STIMULI : process
  variable L_IN : line;
  variable CHAR : character;
  variable DATA_1, DATA_2 : std_logic_vector(7 downto 0);
  file STIM_IN : text is in
                "stim_in.txt";
begin
  while not endfile(STIM_IN) loop
    readline(STIM_IN, L_IN);
    hread(L_IN, DATA_1);
    W_VALUE_1 <= DATA_1;
    read(L_IN, CHAR);
    hread(L_IN, DATA_2);
    W_VALUE_2 <= DATA_2;
    wait for PERIOD;
  end loop;
  wait;
end process STIMULI;
  • Stimuli file “stim_in.txt”
    • Each line contains two hex values to stimulate the inputs of the ADDER module
00 A1
FF 01
FF 00
11 55
0F 01
1F 05
AA F3

Notes

After having instantiated the entity ADDER, a stimuli process is needed that provides the test patterns.

The stimuli are read from the file “stim_in.txt”.

Reading the file works as follows:

  • It is checked, whether the stumli file STIM_IN still contains data. If so, the following statements will be executed, otherwise they will be skipped and the process will suspend at the last ’wait’ statement of this process.
  • First one line L_IN is read from the file STIM_IN by the ’readline’ command. Afterwards, three different values, an 8 bit standard logic vector, followed by a single character and another 8 bit vector are extracted from this line L_IN. The data type is selected by the data type of the variable used in the READ procedure. HREAD is also a kind of read command which transforms the value read from hexadecimal to ’std_logic_vector’ automatically.

HREAD is contained in the STD_LOGIC_TEXTIO package.

After the values from the file are stored in the variables, they have to be assigned to the signals that are connected to the input ports of the DUT.

After finishing one line, the process waits for one PERIOD before checking again, whether the stimuli file STIM_IN still contains some data.

  • Response process of the testbench
    • ’NOW’ is a function returning the current simulation time
    • Several write commands assemble a line
    • Writeline saves this line in the file
    • The function hwrite(…) is defined in the IEEE.std_logic_textio package; it transforms a binary vector to a hex value and stores it in the line
RESPONSE : process(W_RESULT)
  variable L_OUT : line;
  variable CHAR_SPACE : character
                           := ’ ’;
  file STIM_OUT : text is out
                 "stim_out.txt";
begin
  write(L_OUT, now);
  write(L_OUT, CHAR_SPACE);
  write(L_OUT, W_RESULT);
  write(L_OUT, CHAR_SPACE);
  hwrite(L_OUT, W_RESULT);
  write(L_OUT, CHAR_SPACE);
  write(L_OUT, W_OVERFLOW);
  writeline(STIM_OUT, L_OUT);
end process RESPONSE;
  • Response file “stim_out.txt”
    • 4 columns containing:
    • Simulation time
    • 8 bit result value (binary and hex)
    • Overflow bit
  0 NS 00000000 00 0
 20 NS 10100001 A1 0
 40 NS 00000000 00 1
 60 NS 11111111 FF 0
 80 NS 01100110 66 0
100 NS 00010000 10 0
120 NS 00100100 24 0
140 NS 10011101 9D 1

Notes

The file output is just the inverse of the file input presented before:

A line has to be composed and written to the file when finished.

The RESPONSE process stores the current simulation time, the RESULT as ’std_logic_vector’ and in hexadecimal format and the OVERFLOW signal.

The process is activated whenever an event occurs at W_RESULT (sensitivity list).

procedure READ_STIM (
               STIM_FILE : in string;
                     ••• );
  file FILE_IN : text is in STIM_FILE;
  variable STIM_LINE : line ;
  •••
end READ_STIM
 
procedure WRITE_RESP ( RESP_FILE : in string;
                       ••• );
  file FILE_OUT : text is out RESP_FILE;
  variable RESP_LINE : line ;
  •••
end WRITE_RESP
STIM: process
  file STIM_FILE : text is "INPUT.TXT";
  variable STIM_LINE : line ;
begin
  readline(STIM_FILE, STIM_LINE);
  •••
  file_close(STIM_FILE);
  file_open(STIM_FILE, "INPUT.TXT", WRITE_MODE);
  •••
  writeline(STIM_FILE, STIM_LINE);
end process STIM;
  • VHDL’87
    • Mode determines if file is readable or writeable
    • Procedure elaborated when called ⇒ Files also opened and closed with entering and exiting procedure
    • Now the same file can be written and read afterwards.
  • VHDL’93
    • Default is READ_MODE
    • Files can be closed and opened with procedure calls
    • Procedures are declared implicit with file declaration

Notes

The file declaration in VHDL’87 is not compatible with that of VHDL’93. In VHDL’87 the file was declared with mode ’in’ or mode ’out’ and could therefore only be read or written.

To circumvent the drawback, one had to write the whole reading and writing processes into two separated procedures. So the files could be opened by calling the corresponding procedure and were closed automatically when the procedure was exited. With this the same file could be written and read afterwards in the same simulation.

In VHDL’93 the modes are called WRITE_MODE and READ_MODE. When a file is declared the procedures FILE_CLOSE and FILE_OPEN are declared implicit with it. This procedures can not be found in the predifined package ’textio’ but have to be implemented in the simulator! So in VHDL’93 it is possible to write and read the same file in the same simulation by using these procedures.


Chapters of System Design > Simulation