Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
11 years ago

file read and write function fails to execute in functions

Working on migrating old code into the next FPGA generation. That means the code worked fine over the last twenty years and had a few migration since utilizing non Altera FPGAs and tools. Now I am trying to compile the code, that was written as standard IEEE 93 VHDL into Altera’s Max 10 family, using the Quartus Prime Version 15.1.0.

I got a lot of surprises during compiling and found that standard code is not executing correctly. However, for most of the issues I was able to work around. But this one is such a trivial standard code, that I think Altera has an issue in its internal code in conjunction when file operations and report calls are made in a function.

The code example below is supposed to save hex data from a file into ROM, for later read out into a special SPI interface that initializes the analog ASICS on the board. Wasting hours of simulating and testing I found out that the following one or two line(s) is (are) not correctly executed. < readline (RomFile, RomFileLine) ; > respective < read(RomFileLine, zahl); >. All values in the AnaConfigROM are 0. If I pass the instruction < Zahl := "A5"; > before the call to < ROM(add_i) := Hex2Vector(Zahl); > then the ROM will be initialized with the value hex A5 (see code) so the rest of the code works. Also the count of the number of hex values in the file with the number of ROM values is correctly, in other words the EOF statement of the file is correctly.

I try to add an output file "debug.txt” to dump “Zahl” back but it does not execute those write statements either.

Does someone know what the issue is, and how to work around? (Going into the schematic editor and using lpm_rom or so is not an option.)

Please find below the code ( I deleted stuff out to keep it short)

-- Memory ROM File for configuration of the Analog ASICS

LIBRARY ieee;

USE ieee.std_logic_1164.all;

use ieee.numeric_std.all;

use std.textio.all; -- used for file access and manipulation

-- Entity Declaration

ENTITY AnalogConfigROMFile IS

-- {{ALTERA_IO_BEGIN}} DO NOT REMOVE THIS LINE!

PORT

(

DigtalReset, AddressClock : In std_Ulogic;

Data : out std_ulogic_vector ( 7 downto 0 );

FileEnd : out std_Ulogic

);

-- {{ALTERA_IO_END}} DO NOT REMOVE THIS LINE!

END AnalogConfigROMFile;

-- Architecture Body

ARCHITECTURE RTL_AnalogConfigROMFile OF AnalogConfigROMFile IS

signal Addr : integer range 0 to 4096; -- 4kByte address space (12 bit addressing)

type ROM_Table is array (Natural range <>) of std_ulogic_vector(7 downto 0); -- undifined size array with 8 bit data value

type ROM_int_Table is array (Natural range <>) of integer;

type FileType is file of text;

SUBTYPE NIBBLE IS std_ulogic_vector (3 DOWNTO 0);

SUBTYPE BYTE IS std_ulogic_vector (7 DOWNTO 0);

SUBTYPE WORD IS std_ulogic_vector (15 DOWNTO 0);

SUBTYPE decimal_digit IS INTEGER RANGE 0 TO 9;

-- translate Hex string to vector

function Hex2Vector(stringZahl : in string ) return BYTE is

variable NibbHigh, Nibb : NIBBLE;

--debug variable

variable debugstr : line;

Begin

-- this is a debug test that does not work too.

report ("Alfa Zahl is =" & stringZahl); -- error --> does not report

write(debugstr, "Alfa Zahl is = "); -- error --> does not write

write(debugstr, stringZahl); -- error --> does not write

writeline(output, debugstr); -- error --> does not write to stdout

-- end not woring debug test

for i in 1 to 2 loop

NibbHigh := Nibb;

Case (stringZahl(i)) is

when '0' => Nibb := "0000";

When '1' => Nibb := "0001";

When '2' => Nibb := "0010";

When '3' => Nibb := "0011";

When '4' => Nibb := "0100";

When '5' => Nibb := "0101";

When '6' => Nibb := "0110";

When '7' => Nibb := "0111";

When '8' => Nibb := "1000";

When '9' => Nibb := "1001";

When 'A' => Nibb := "1010";

When 'B' => Nibb := "1011";

When 'C' => Nibb := "1100";

When 'D' => Nibb := "1101";

When 'E' => Nibb := "1110";

When 'F' => Nibb := "1111";

When 'a' => Nibb := "1010";

When 'b' => Nibb := "1011";

When 'c' => Nibb := "1100";

When 'd' => Nibb := "1101";

When 'e' => Nibb := "1110";

When 'f' => Nibb := "1111";

when others => Nibb := "0000";

end case;

end loop;

return NibbHigh & Nibb;

end function;

-- *** Read a file into the ROM ***

impure function InitRomFromFile (RomFileName : in string) return ROM_Table is

--file RomFile : text is in RomFileName;

file RomFile : text;

file debugfile : text;

variable RomFileLine : line;

variable ROM : ROM_Table (0 to 4095);

variable Zahl : string (1 to 2);

variable add_i : integer;

-- file outputfile : TEXT open WRITE_MODE is "verify_out.txt";

-- file debugfile : TEXT is out "debug.txt";

variable debugstr : line;

begin

file_open (RomFile, RomFileName, read_mode);

file_open (debugfile, "debug.txt", write_mode);

add_i := 0;

while ( (add_i <= 4095) And (not endfile (RomFile)) ) loop -- Note Reads the eof correctly - loop count is correct!!

-- Note a forced ending for loop <10000 is required;

-- !!! Note the forced ending must be first in the statement or you receive a compiler error

-- !!! while ( (not (endfile (RomFile))) AND (add_i <= 4200) ) loop gives an analysis error !!!

readline (RomFile, RomFileLine); -- error --> unknown if statment works correctly

read(RomFileLine, Zahl); -- error --> the loop is counted correctly but value of zahl is unknown

-- added some debug code -- not working

report ("Beta Zahl is =" & Zahl); -- error --> does not report zahl

write(debugstr, "Beta Zahl is = ");

write(debugstr, Zahl);

writeline(output, debugstr); -- error --> does not write to stdout

writeline(debugfile, debugstr); -- error --> does not create and write to debugfile

-- end debug code

-- Zahl := "A5"; -- using this statment will initialize the ROM with all A5

ROM(add_i) := Hex2Vector(Zahl);

add_i := add_i + 1;

end loop;

file_close(RomFile);

file_close(debugfile);

return ROM;

end function;

-- constant AnaConfigROM : ROM_Table := (X"00",X"FF",X"02",X"03",X"04",X"05",X"D5",X"00" );

constant AnaConfigROM : ROM_Table := InitRomFromFile("AnaROMConfig.txt");

BEGIN

-- Main Process this process is used to return data to the SPI Shift Register

ROM_Read: Process (DigtalReset, AddressClock)

Begin

if DigtalReset = '0' then

Addr <= 0;

Data <= "00000000";

FileEnd <= '0';

elsif rising_edge (AddressClock) then

Data <= AnaConfigROM(Addr);

if Addr < AnaConfigROM'high then

Addr <= Addr + 1;

else

Addr <= 0;

FileEnd <= '1';

end if;

end if;

End Process ROM_Read;

END RTL_AnalogConfigROMFile;

8 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    by the way... this is normal path when you migrate to another newer version.. what is the initial version that you are using correctly? maybe stay with that version unless you want to spend some time to fix those incompatibility problems

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Think migrating to newer device is a form of upgrading own product to remain competitive.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I wonder what tool you were using previously - Quartus doesnt support textio at all and never has done (which is very frustrating when the verilog equivalent IS supported, and textio is supported by Xilinx ISE). Its an enhancement request I made 7 years ago!

    There are only 3 ways to initialise a ROM/RAM:

    1. manually declared array in VHDL

    2. Use a .mif file (which can be assigned via attributes or via the assignments editor)

    3. Use a function that computes values, like a sin function.

    These are the only VHDL supported initialisation methods.

    What synthesis tool were you using previously?

    I suggest making a mysupport request for this enhancement!
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    PS. This gives you a 13 bit address:

    signal Addr : integer range 0 to 4096; -- 4kByte address space (12 bit addressing)

    Because 4096 = 1000000000000

    You need to declare

    signal addr : integer range 0 to 4095;
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thank you Tricky. Yes you are correct, the bus declaration for the address is 0 to 4095, I deleted accidently the line when I try to isolate the problem and coppied the code into a different file. (No wonder, my brain was thinking any more after 13 hours at work).

    The code was running over the time in Xilinx, Lattice, Orca (ATT FPGA) and also in 10k100 (altera), and was compiled with the tools at the time available for those FPGAs.

    It is the first time that Quartus is used at our company, and this code is compiled with this compiler. The last projects with Altera FPGA dated back to 1998. (In the far end of our building are still some old computer with CRT monitors running Max II under windows 95.)

    However, I came to the same conclusion that Quartus compiler does not support VHDL file read ROM configuration. (Could also just be a bug sine the complier does read the file size correctly (opens the file and finds the EOF, but does not fetch the data. I found other deviations form IEEE 95 standard in Quartus compiling that that are definitive software bugs.)

    Our application is very mission critical. And for each different target system we need to create different analog behavior files. The analog data gets created from the simulator and are provided in that “4k” file. I think for right now I have only option 1 available; manually declare an array in VHDL. (Since this impacts the least hand manipulation on the provided analog data file. It is a pain in the b… since I need to change the VHDL file each time.)

    I tried 2 but we would have to make manually too many changes in the file, that’s too risky.

    I was looking into the possibility load the data into the flash after compiling the code, by read the data file into flash via USB cable. That would be the most elegant method we would not have to create for each target a different FPGA image anymore. However, the only Flash IP I find supporting the MAX10 Family uses the Avalon interface.

    I was looking for the user-flash with a parallel interface, but the IP does not support Max10 family.

    The issue I have is that the Avalon interface requires an on chip microprocessor and firmware. My problem firmware and software is a NO_GO for this type of application.

    Any thoughts on that?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    The constant will probably be the easiest. I assume you can just copy/paste the values from the old text file in a decent text editor with column edit mode and just add the text arround the copy/pasted text. Could probable be done in 5 mins.

    As for VHDL support - There is no IEEE 95 VHDL standard. There is '87, 93, 2002 and 2008. There is a 95 Verilog standard if thats what you're refering to? Altera's compile tools have always been one of the better ones. Much better than Xilinx and even synopsys admit their synth engine is no better than Quartus. It also had some 2008 support before anyone else (it's starting to lag now). But otherwise the Altera tools are the rather good. Max + Plus 2 has very poor VHDL support.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    PS. Avalon is just a standard bus protocol - there is nothing to stop you writing your own ip to drive it - no microprocessor required.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thank you Tricky, good to know. I think I need to spend some time to dig me into the Avalon bus protocol. If I can married the USB and the UFM IP together with some bridge Interface, that would kill a lot of my problems.