0
\$\begingroup\$

I have a binary file which represents memory contents of a memory device. I want to load these into my testbench. The hex file obviously is not text file thus no concept of line break and carriage return exists in it.

The problem is that as far as I can see, VHDL only reads text files aka ASCII files. I cannot find a way to read binary files.

The file has no structure as such, all contents in it are to be loaded into std_logic_vector array which shall obviously require parsing.

\$\endgroup\$
  • 1
    \$\begingroup\$ Your title says "binary files" (implying non-text), while the body refers to "a hex file", which WOULD be text (ASCII characters representing hex digits). Which is it? Also, what simulator are you using? \$\endgroup\$ – Dave Tweed Sep 21 '16 at 2:03
  • \$\begingroup\$ I have made the correction in the question. The file I have is not human readable. Thus you are correct, it is not a hex file. It just contains a continuous stream of bytes. These can have any value, even be equal to what in ASCII are line break and carriage return. Every byte is to be read into a std_logic_vector. \$\endgroup\$ – quantum231 Sep 21 '16 at 7:51
2
\$\begingroup\$

Firstly, hex file are text files. Secondly, I have found it easier to write scripts to parse the external files in VHDL, than to use VHDLs limited text processing capabilities.

Another option you have is to use some of the RAM of the FPGA. You can configure the RAM using your hex file. This is perfect if you are testing internal memory.

A cautionary note: text IO is not supported by many IDEs for synthesis, even though it is in the VHDL spec. I once lost a few hours parsing text in VHDL only to find it will not synthesize.

Edit I know this is not an answer to the original question, but I wanted to point out that there are better tools for the task. You can save yourself a lot of headaches by using a parsing library.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ The answers you have given is helpful. However, I made a mistake in my question. The file is a binary file containing stream of bytes. It is not human readable. You are correct in that if I have a hex file, I could for example instantiate a FPGA memory block and set it to load initial comments from the hex file. \$\endgroup\$ – quantum231 Sep 21 '16 at 7:55
  • \$\begingroup\$ @quantum231 I would write a script to parse it then. I don't know what you mean by hex here. Does it comply to a standard etc.? If it is not too complicated, you can simply read the file and generate the appropriate std_logic assignments. Or you can output a memory file, like this one, and initialize internal RAM. \$\endgroup\$ – user110971 Sep 21 '16 at 8:01
  • \$\begingroup\$ The file I have is not hex. I realized that hex files are in fact ASCII files. What I have is a binary file which is not human readable. The problem is that if I used read line, any line break character would be taken as line break rather than a byte to be read into the test bench and stored. That is the fundamental problem. \$\endgroup\$ – quantum231 Sep 21 '16 at 9:40
  • \$\begingroup\$ @quantum231 I'd use a parser as I said. You said it is a stream of bytes. If that is the case, it should be straight forward to write a script to convert it into whatever you want i.e.: ASCII, VHDL code, memory initialization file etc. \$\endgroup\$ – user110971 Sep 21 '16 at 11:55
  • \$\begingroup\$ Eventually I decided to write a C++ program using OOP technique to read a raw binary file and covert it into ASCII hex file which is then read by the tesbench (parsed) and the signal representing memory is filled in. To simplify the process I wrote a new package for the Flash memory containing functions needed in simulation and modeled the flash using VHDL protected type to get in effect a BFM since I do not know SystemVerilog at this stage. Overall it worked out. Thanks for the recommendation. \$\endgroup\$ – quantum231 Oct 27 '16 at 20:50
2
\$\begingroup\$

Yes, VHDL can read and write binary files. However, there are no guarantees as to the exact file format, other than that you can read in a file you wrote out earlier, with the same version of the same simulator. (this was about ten years ago so forgive any haziness in the details)

By experiment, I found that in Modelsim. binary files are pretty much as expected (though I can't remember if it used a big-endian or little-endian byte order in the file).

Xilinx ISIM used the opposite endian-ness, and added/expected a 9 byte header before the data, rejecting files without that header. Xilinx also explicitly refused my request for documentation on the header format, so I resorted to extracting it from one file and prepending it to others, via head, tail and cat (on Linux, obviously). I used a boolean generic, "is_isim" to control endian-swapping according to the simulator.

I haven't tried porting these old testbenches to ghdl, but it is likely to be similar to Modelsim in its ease of use here.

In either case, you read binary data into an Tnteger, 32-bit words at a time, and translated from there into std_logic_vector or records or other types as appropriate (in my case, the files were SEG-Y format, a binary file used in geophysics)

If you're intimately familiar with Python, a script will be easier, but VHDL's strictness and emphasis on compile time checking makes getting the expected results via the VHDL route pretty easy once you get over the initial hump.


Binary file access...

From the LRM (VHDL-2008) (edited for brevity):

5.5 File types
5.5.1 General
file_type_definition ::= file of type_mark

Example :

type IntFile is file of integer;

5.5.2 File operations
Given the following file type declaration:
type FT is file of TM;
the following operations are implicitly declared immediately following the file type declaration:
procedure FILE_OPEN (file F: FT; External_Name: in STRING;
Open_Kind: in FILE_OPEN_KIND := READ_MODE);
procedure FILE_CLOSE (file F: FT);
procedure READ (file F: FT; VALUE: out TM);
procedure WRITE (file F: FT; VALUE: in TM);
procedure FLUSH (file F: FT);
function ENDFILE (file F: FT) return BOOLEAN;

Example:

procedure ReadFile is
   file MyFile : IntFile;
   variable i : integer;
begin
   File_Open(MyFile,"beethoven_5.wav");
   while not EndFile(MyFile) loop
      Read(MyFile,I);
      Audio_Dac <= I;
   end loop;
   File_Close(My_File);
end ReadFile;

Note that this doesn't parse WAV files properly so will probably not play Beethoven's Fifth Symphony in your simulator. And if your file is a whole number of bytes, but not of 32-bit integers, you can treat it as a file of character and use character'pos and 'val attributes to translate to integers.

You may be able to treat it as a file of bit_vector(7 downto 0) but I haven't tried recently.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Vhdl uses readline followed by read to read in files. In a binary file the byte corresponding to line break or carriage return is in fact just another byte with no interpretation. If one was to use readline which is how vhdl works, wouldn't that miss out the bytes that read as line break from being read into the test bench? I mean a binary file really is just a single continuous line, has no concept of line breaks. Line break character, if encountered, does not mean line break. \$\endgroup\$ – quantum231 Sep 21 '16 at 9:43
  • \$\begingroup\$ No, that's how VHDL reads text files. You don't use readline for non-text files. I'll need to look at some (very old) notes to say more, or the LRM. \$\endgroup\$ – Brian Drummond Sep 21 '16 at 9:50
  • \$\begingroup\$ Thanks Brain. In the line "type FT is file of TM" what does TM mean? Is this from the textio package or some other package? I have only seen read procedure that takes a line as one parameter inout. Here though the read function actually takes the file as a parameter. Quite fascinated to see that. \$\endgroup\$ – quantum231 Sep 21 '16 at 23:46
  • \$\begingroup\$ No, it's from the LRM, chapter 5.5.1 and 2. I should have included the BNF, file_type_definition ::= file of type_mark which makes it clear that TM is a "type mark" i.e. the name of any (simple? discrete?) type already declared. So, for text IO, TM would have to be a character, allowing you to read a character at a time. Then the std.text_io package provides better abstractions over such low level file I/O. \$\endgroup\$ – Brian Drummond Sep 22 '16 at 10:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.