Site hosted by Angelfire.com: Build your free website today!
undefined
undefined

Reading files from Verilog models

Introduction

This guide describes how you can read files in a Verilog model using a set of system functions which are based on the C stdio package. With these system functions you can perform file input directly in Verilog models without having to learn C or the PLI. Download read.tar.gz, the Unix version of the code, plus documentation and examples. This works with VCS and Verilog-XL but not NC-Verilog.

[Up


Copyright

All code and this user guide are copyright (C) 1995 -1997 by Christian B. Spear, spear@viewlogic.com, (508) 303-5252 If you have any updates, bug fixes, or enhancements, or want the latest version, please contact me.

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 


Overview

This application note describes how your Verilog model or testbench can read text and binary Unix files to load memories, apply stimulus, and control simulation. The format of the file-read functions is based on the C stdio routines, such as fopen, fgetc, and fscan.

The Verilog language has a rich set of system functions to write files ($fdisplay, $fwrite, etc.) but only reads files with a single, fixed format ($readmem). In the past if you wanted to read a file that was not in $readmem format, you would have to learn the Programming Language Interface (PLI) and the C language, write C code to read the file and pass values into Verilog, then debug the combined C and Verilog code.

However, using the new file-read system functions you can perform your file I/O directly from Verilog. You can write Verilog HDL to:

Code for all the examples is included in the examples directory for the file-read functions.

Note that these system tasks behave the same as the equivalent stdio routines. For example, $fscanf will skip over white-space, including blank lines, just like fscanf(). You can prototype code in C then convert it to Verilog.


File Input Functions

The file-read system functions and tasks are based on the C stdio routines. For more information on the stdio routines, consult a C manual. The major differences between these system tasks and C are caused by the lack of a pointer variable in the Verilog language. Strings in Verilog are stored in registers, with 8 bits needed to store a single character.

OPEN A FILE

integer file;
file = $fopenr("filename");

The function $fopenr opens a file for reading. The file name can be either a quoted string or a reg holding the file name. If the file was successfully opened, it returns an integer containing the file number (1..MAX_FILES) or EOF (-1) if there was an error. Note that this is not the same function as $fopen which opens a file for writing.

CLOSE A FILE

integer file, r;
r = $fcloser(file);

The function $fcloser closes a file for input. It returns EOF if there was an error, otherwise 0. Note that this is not the same task as $fclose which closes files for writing.

TEST FOR END OF FILE

integer file;
reg eof;
eof = $feof(file);

The function $feof tests for end of file. If an end-of-file has been reached while reading from the file, a non-zero value is returned; otherwise, a 0 is returned.

READ A SINGLE CHARACTER

integer file, char;
char = $fgetc(file);

The function $fgetc reads a single character from the specified file and returns it. If the end-of-file is reached, $fgetc returns EOF. You should use a 32-bit register to hold the result from $fgetc to tell the difference between the character with the value 255 and EOF.

PUSH BACK A CHARACTER

integer file;
reg [7:0] char, r;
r = $ungetc(char, file);

The function $ungetc pushes the character back into the file stream. That character will be the next read by $fgetc. It returns the character if it was successfully pushed back or EOF if it fails.

READ A STRING

integer file, n, r;
reg [n*8-1:0] string;
r = $fgets(string, n, file);

The function $fgets reads a string from the file. Characters are read from the file into string until a newline is seen, end-of-file is reached, or n-1 characters have been read. If the end-of-file is encountered, $fgets returns a 0 and string is unchanged; otherwise, $fgets returns a 1.

READ FORMATTED TEXT

integer file, count;
count = $fscanf(file, format, args);
count = $sscanf(string, format, args);

The function $fscanf parses formatted text from the file according to the format and writes the results to args . $sscanf parses formatted text from a string. See a C reference manual for detailed information on fscanf, plus examples later in this note.

The format can be either a string constant or a reg. It can contain:

The addl_args is an optional list of registers to be assigned by $fscanf and $sscanf. There must be a register for each conversion operator (except those with %*). Bit subscripts are ignored.

$fscanf and $sscanf return the number of successful assignments performed.

FIND THE FILE POSITION

integer file, position;
position = $ftell(file);

The function $ftell returns the position in the file for use by $fseek. If there is an error, it returns a -1.

POSITION A FILE

`define SEEK_SET 0
`define SEEK_CUR 1
`define SEEK_END 2
integer file, offset, position, r;
r = $fseek(file, 0, `SEEK_SET); /* Beginning */
r = $fseek(file, 0, `SEEK_CUR); /* No effect */
r = $fseek(file, 0, `SEEK_END); /* End of file */
r = $fseek(file, position, `SEEK_SET); /* Previous loc */

The function $fseek allows random access in a file. You can position at the beginning or end of a file, or use the position returned from $ftell.

READ BINARY DATA

integer r, file, start, count;
reg [15:0] mem[0:10], r16;
r = $fread(file, mem[0], start, count);
r = $fread(file, r16);

The function $fread reads a binary file into a Verilog memory. The first argument is either a register or a memory name, which must have a subscript, though the value of the subscript is ignored. start and count are optional.

By default $fread will store data in the first data location through the final location. For the memory up[10:20], the first location loaded would be up[10], then up[11]. For down[20:10], the first location would be down[10], then down[11].

start and count are ignored if $fread storing data in a reg instead of a memory. No warning is printed if the file contains more data than will fit in the memory.

start is the word offset from the lowest element in the memory. For start = 2 and the memory up[10:20], the first data would be loaded at up[12]. For the memory down[20:10] , the first location loaded would be down[12], then down[13].

$fread returns the number of elements read from the file, If $fread terminates early because of an error, it will return the number of elements successfully read. $feof can be used to determine whether the end-of-file was reached during $fread.

The data in the file is broken into bytes according to the width of the memory. An 8-bit wide memory takes one byte per location, while a 9-bit wide memory takes 2 bytes. Care should be taken when using memories with widths not evenly divisible by 8 as there may be gaps in the data in the memory vs. data in the file. 


Restrictions and Caveats

You should be aware of following restrictions in using these Verilog functions vs. the stdio functions in C, which are imposed by the Verilog language : r = $fscanf(...)
while (c=fgetc(stream) != EOF) {
<process input>
}

turns into the Verilog code:
c = $fgetc(file);
while (c !== `EOF) 
begin
<process input>
c = $fgetc(file);
end

In addition, $save / $restart are loosely supported with VCS on SunOS. In a test, $feof never returned EOF when running from a save file, but $fgetc did. On other simulators and hardware platforms you can mimic these functions using $ftell and $fseek to find the position in a file and later jump to that location.

The maximum number of files (MAX_FILES) is set in the C code to 12. The maximum string size is 1000 characters. There is no known limit to the number of conversion operators in $fscanf or $sscanf. 


Reading pattern files

This first example shows how to read input stimulus from a text file.

This is the pattern file - read_pattern.pat , included in the examples directory:

// This is a pattern file
// time bin dec hex
10: 001 1 1
20.0: 010 20 020
50.02: 111 5 FFF
62.345: 100 4 DEADBEEF
75.789: XXX 2 ZzZzZzZz

Note that the binary and hexadecimal values have X and Z values, but these are not allowed in the decimal values. You can use white space when formatting your file to make it more readable. Lastly, any line beginning with a / is treated as a comment.

The module read_pattern.v reads the time for the next pattern from an ASCII file. It then waits until the absolute time specified in the input file, and reads the new values for the input signals (bin, dec, hex). The time in the file is a real value and, when used in a delay, is rounded according to the timescale directive. Thus the time 75.789 is rounded to 75.79 ns.

`timescale 1ns / 10 ps 
`define EOF 32'hFFFF_FFFF 
`define NULL 0 
`define MAX_LINE_LENGTH 1000 
  
module read_pattern; 
integer file, c, r; 
reg [3:0] bin; 
reg [31:0] dec, hex; 
real real_time; 
reg [8*`MAX_LINE_LENGTH:0] line; /* Line of text read from file */ 
  
initial 
    begin : file_block 
    $timeformat(-9, 3, "ns", 6); 
    $display("time bin decimal hex"); 
    file = $fopenr("read_pattern.pat"); 
    if (file == `NULL) // If error opening file 
        disable file_block; // Just quit 
  
    c = $fgetc(file); 
    while (c != `EOF) 
        begin 
        /* Check the first character for comment */ 
        if (c == "/") 
            r = $fgets(line, `MAX_LINE_LENGTH, file); 
        else 
            begin 
            // Push the character back to the file then read the next time 
            r = $ungetc(c, file); 
            r = $fscanf(file," %f:\n", real_time); 
  
            // Wait until the absolute time in the file, then read stimulus 
            if ($realtime > real_time) 
                $display("Error - absolute time in file is out of order - %t", 
                        real_time); 
                else 
                    #(real_time - $realtime) 
                        r = $fscanf(file," %b %d %h\n",bin,dec,hex); 
                end // if c else 
            c = $fgetc(file); 
        end // while not EOF 
  
    r = $fcloser(file); 
    end // initial 
  
// Display changes to the signals 
always @(bin or dec or hex) 
    $display("%t %b %d %h", $realtime, bin, dec, hex); 
  
endmodule // read_pattern


Comparing outputs with expected results

The following model, compare.v, reads a file containing both stimulus and expected results. The input signals are toggled at the beginning of a clock cycle and the output is compared just before the end of the cycle. 
  
`define EOF 32'hFFFF_FFFF 
`define NULL 0 
`define MAX_LINE_LENGTH 1000 
module compare; 
integer file, r; 
reg a, b, expect, clock; 
wire out; 
reg [`MAX_LINE_LENGTH*8:1]; 
parameter cycle = 20; 
  
initial 
    begin : file_block 
    $display("Time Stim Expect Output"); 
    clock = 0; 

    file = $fopenr("compare.pat"); 
    if (file == `NULL) 
        disable file_block; 
  
    r = $fgets(line, MAX_LINE_LENGTH, file); // Skip comments 
    r = $fgets(line, MAX_LINE_LENGTH, file); 

    while (!$feof(file)) 
        begin 
        // Wait until rising clock, read stimulus 
        @(posedge clock) 
        r = $fscanf(file, " %b %b %b\n", a, b, expect); 
  
        // Wait just before the end of cycle to do compare 
        #(cycle - 1) 
        $display("%d %b %b %b %b", $stime, a, b, expect, out); 
        $strobe_compare(expect, out); 
        end // while not EOF 
  
    r = $fcloser(file); 
    $stop; 
    end // initial 
  
always #(cycle / 2) clock = !clock; // Clock generator 

and #4 (out, a, b); // Circuit under test 
endmodule // compare


Reading script files

Sometimes a detailed simulation model for a device is not available, such as a microprocessor. As a substitute, you can write a bus-functional model which reads a script of bus transactions and performs these actions. The following, script.v, reads a file with commands plus data values. 
  
`define EOF 32'hFFFF_FFFF 
`define NULL 0 
module script; 
integer file, r; 
reg [80*8:1] command; 
reg [31:0] addr, data; 
  
initial 
    begin : file_block 
    clock = 0; 
  
    file = $fopenr("script.txt"); 
    if (file == `NULL) 
        disable file_block; 
  
    while (!$feof(file)) 
        begin 
        r = $fscanf(file, " %s %h %h \n", command, addr, data); 
        case (command) 
        "read": 
            $display("READ mem[%h], expect = %h", addr, data); 
        "write": 
            $display("WRITE mem[%h] = %h", addr, data); 
        default: 
            $display("Unknown command '%0s'", command); 
        endcase 
        end // while not EOF 
  
    r = $fcloser(file); 
    end // initial 
endmodule // script 

The file script.txt is the script read by the above model:
read 9 0
write 300a feedface
read 2FF xxxxxxxx
bad


Reading data files into memories

Reading a formatted ASCII file is easy with the system tasks. The following is an example of reading a binary file into a Verilog memory. $fread can also read a file one word at a time and copy the word into memory, but this is about 100 times slower than using $fread to read the entire array directly.

This is the file load_mem.v

`define EOF 32'HFFFF_FFFF 
`define MEM_SIZE 200_000 
  
module load_mem; 
  
integer file, i; 
reg [7:0] mem[0:`MEM_SIZE]; 
reg [80*8:1] file_name; 
  
initial 
    begin 
    file_name = "data.bin"; 
    file = $fopenr(file_name); 
    i = $fread(file, mem[0]); 
    $display("Loaded %0d entries \n", i); 
    i = $fcloser(file); 
    $stop; 
    end 
  
endmodule // load_mem 

The file data.bin contains the 200 binary values 0 to 199. You can look at the program data.c which generated the file. To dump out the binary file in Unix use the command od data.bin

Linking with VCS

To use the file-read system functions with Chronologic VCS, you will need to:
  1. Compile read.c with the command:

  2. cc -c read.c -I$VCS_HOME/sparc/lib

    On the DEC/Alpha use
    cc -c read.c -I$VCS_HOME/alpha/lib -taso -xtaso_short

  3. Compile and your Verilog model with:
  
% vcs load_mem.v read.o -P read_pli.tab -R 
Chronologic Simulation VCS Release 2.4 
Copyright Chronologic Simulation 1991-1994. All Rights Reserved. 
This Licensed Software contains Confidential and proprietary information 
which is the property of Chronologic Simulation 
Compiling load_mem.v 
Top Level Modules: 
load_mem 
( cd csrc ; make -f Makefile DEFAULT_RUNTIME=TRUE product ) 
../simv up to date 
Running simv -V -a vcs.compile.log 
Chronologic Simulation VCS simulator copyright 1991-1994 
Chronologic Simulation VCS simulator contains proprietary information. 
Compiler version 2.4; runtime version 2.4 
  
Loaded 200 entries 
  
$stop at time 0 Scope: load_mem File: load_mem.v Line: 13 
cli_0 > 


Linking with Verilog-XL

To use the file-read system functions with Verilog-XL, you will need to:
  1. Modify veriuser.c to point to the system functions in read.c . You should copy these two files into your current directory from the examples directory.
  2. Type vconfig to generate a script to link Verilog-XL. Use the following table to choose your responses.

Running vconfig 

Prompt issued from vconfig : 

You type: 

Please choose a platform 1, 2, 3, or 4 
Please enter the name of the output script cr_vlog_read
Please choose a target 1
What do you want to name the Verilog-XL target?  verilog_read
Do you want to compile for the Verilog-XL environment?  return
Do you want to include the dynamic LAI interface?  return
Do you want to include STATIC LOGIC AUTOMATION models in this executable?  return
Do you want to include the LMSI HARDWARE MODELER interface software in this executable?  return
Do you want to include the Verilog Mixed-Signal interface software in this executable?  return
Do you want to include the CDC in this Verilog-XL?  return
Do you want to include the Standard Delay File Annotator in this executable?  return
The user template file 'veriuser.c' must always be included in the link statement. What is the path name of this file?  ./veriuser.c
Please list any other user files to be linked with this Verilog-XL ... terminating with a single '.'  ./read.c

. (period)

  
% ./verilog_read load_mem.v 
VERILOG-XL 2.1.12 Jun 21, 1995 14:55:32 
  
Copyright (c) 1994 Cadence Design Systems, Inc. All Rights Reserved. 
. 
. 
. 
<<< Routines for file read linked in >> 
Compiling source file "load_mem.v" 
Highest level modules: 
load_mem 
  
Loaded 200 entries 
  
L13 "load_mem.v": $stop at simulation time 0 
Type ? for help 
C1>


If you experience any difficulty in downloading the source file please email Rajesh Bawankule


Go back to Alternate Verilog FAQ Page