I have a VHDL testbench where I would like to write 32-bit binary words to a file for testing. Below is a minimal, complete, verifiable example.
When executed with GHDL (commands below) an overflow is generated at the indicated line. If the line is commented out execution completes successfully and writes the file. The overflow occurs anytime the high bit is set.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
use std.env.stop;
entity u32_file_write is
end entity;
architecture rtl of u32_file_write is
type intFileType is file of natural;
file fh : intFileType;
begin
run: process
variable no_high_bit : std_logic_vector(31 downto 0) := x"7FFFFFFF";
variable with_high_bit : std_logic_vector(31 downto 0) := x"FFFFFFFF";
begin
file_open(fh, "out.bin", write_mode);
write(fh, to_integer(unsigned(no_high_bit)));
write(fh, to_integer(unsigned(with_high_bit))); -- Overflow here.
file_close(fh);
stop;
end process;
end architecture;
I run the following GHDL commands to run the VHDL code (save as u32_file_write.vhd
):
ghdl -a -fexplicit --std=08 --ieee=synopsys u32_file_write.vhd
ghdl -e -fexplicit --std=08 --ieee=synopsys u32_file_write
ghdl -r -fexplicit --std=08 --ieee=synopsys u32_file_write
With the line commented out, the corrected results are written to the file:
% od -tx4 out.bin
0000000 7fffffff
If the line is uncommented, an overflow is generated:
ghdl:error: overflow detected
from: ieee.numeric_std.to_integer at numeric_std-body.vhdl:3040
ghdl:error: simulation failed
As noted above, the write will work with any value in the first 31-bits. The write will overflow with any value where the 32-bit is set.
The underlying problem is integer'high is 2^31-1. See:
The accepted answer here states to use an intermediate 'text' format a text processing language. Another answer shows a solution for reading using 'pos but that doesn't help me write.
Is there a simple rework/workaround that will allow me to write all 32-bits of data to a binary file?
Change your file type to character. Convert 8 bits at a time to character and write all four characters to the file,
With 8 bit writes you're responsible for getting the endian order correct.
You can do that with a write procedure tailored to write 32 bit unsigned values to the character file:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
use std.env.stop;
entity u32_file_write is
end entity;
architecture foo of u32_file_write is
-- type intFileType is file of natural;
type intFileType is file of character; -- CHANGED type mark
file fh : intFileType;
procedure write (file cf: intFileType; val: unsigned (31 downto 0)) is
begin
write (cf, character'val(to_integer(val( 7 downto 0))));
write (cf, character'val(to_integer(val(15 downto 8))));
write (cf, character'val(to_integer(val(23 downto 16))));
write (cf, character'val(to_integer(val(31 downto 24))));
end procedure;
begin
run: process
variable no_high_bit : std_logic_vector(31 downto 0) := x"7FFFFFFF";
variable with_high_bit : std_logic_vector(31 downto 0) := x"FFFFFFFF";
begin
file_open(fh, "out.bin", write_mode);
-- write(fh, to_integer(unsigned(no_high_bit)));
-- write(fh, to_integer(unsigned(with_high_bit))); -- Overflow here.
write (fh, unsigned(no_high_bit));
write (fh, unsigned(with_high_bit));
file_close(fh);
stop;
end process;
end architecture;
ghdl -a -fexplicit --std=08 --ieee=synopsys u32_file_write.vhdl ghdl -e -fexplicit --std=08 --ieee=synopsys u32_file_write ghdl -r -fexplicit --std=08 --ieee=synopsys u32_file_write
Note that the only command line argument besides the command (-a, -e, -r) required here is --std-08 because of stop
. There are no Synopsys package dependencies nor a requirement for -fexplicit (which isn't depended on either).
od -tx4 out.bin 0000000 7fffffff ffffffff 0000010
A host's file system contains files that consist of an array of 8 bit characters. It's convention (format) that superimposes the idea of something bigger.
VHDL superimposes type on file transactions, unfortunately there's no way to declare a natural range value greater than 2 ** 31 -1, if your integers were bigger they wouldn't be portable.
The above method treats files as character files allowing superimposition of size of elements of the contents by conventions (here in the host system, if you want to read 32 bit unsigned you'd want to read 4 characters and assemble a 32 bit value in the correct endian order).
An unsigned_int here is a 32 bit unsigned value. Note that the ascending or descending order isn't required to match in a subprogram call because of implicit subtype conversion (formals and actuals elements are associated in left to right order here).
The author of the original post encountered a problem reported in a comment:
The write() above generates an error during analysis:
u32_file_write.vhd:23:14:error: cannot resolve overloading for subprogram call.The error repeats four times, once for each write(). I've not found a way to get GHDL to write raw bytes other than an integer.
Line 23 in the comment appears to correspond to the 18th line above where character 14 is the parameter list of the first write procedure call write[file IntFileType, character]
which suggests the declaration for type IntFileType
's type definition's type mark hasn't been changed to type character
. The signature of the procedure calls would not match those of the implicitly declared write for file type IntFileType
, also noting the line numbers don't match.
The code has been provided complete in this answer to allow copying in it's entirety from the question, which was done along with naming the design file with a .vhdl suffix and using the command lines above.
The version of ghdl used is a recent build (GHDL 0.36-dev (v0.35-259-g4b16ef4)) built with an AdaCore 2015 GPL gnat (GPL 2015 (20150428-49)) and tested with both the llvm backend code generator (clang+llvm-3.8.0) and mcode code generator both on MacOS (10.11.6, gnat-gpl-2015-x86_64-darwin-bin and clang+llvm-3.8.0-x86_64-apple-darwin, using Xcode 8.2.1).
(The endian order of the character writes from val in the new write procedure has been reversed to match the OP's od -xt out.bin
result byte order )