1
\$\begingroup\$

I am trying to model a memory which shall store instructions for a processor design. These instructions are stored in a text file as 32 bit binary words. At start of simulation all values must be copied into an std_logic_vector array in the memory block from this text file and then a value at a time shall be output depending on the address supplied to the memory. How can I achieve this?

Apparently I need ieee.std_logic_textio.all; along with std.textio.all; and I can only use the read/write functions with variables. If the std_logic_vector array is a signal, it shall not update as soon as I write to it. I am confused on how to do this properly. I won't have any more than 1023 instructions in the text file since I do not want the simulation to use too much RAM.

\$\endgroup\$
3
\$\begingroup\$

Here is a simple example function that reads a *.hex file from disk and initializes a RAM.

A hex file stores one RAM word per line in hexadecimal encoding (ASCII chars: 0-9, A-F, a-f)

At first a memory needs to be defined by word_t and ram_t. The generics or constants DATA_BITS and DEPTH define the memory layout:

subtype word_t  is std_logic_vector(DATA_BITS - 1 downto 0);
type    ram_t   is array(0 to DEPTH - 1) of word_t;

Secondly, a function is defined to read a file and return a initialization vector:

-- Read a *.hex file
impure function ocram_ReadMemFile(FileName : STRING) return ram_t is
  file FileHandle       : TEXT open READ_MODE is FileName;
  variable CurrentLine  : LINE;
  variable TempWord     : STD_LOGIC_VECTOR((div_ceil(word_t'length, 4) * 4) - 1 downto 0);
  variable Result       : ram_t    := (others => (others => '0'));

begin
  for i in 0 to DEPTH - 1 loop
    exit when endfile(FileHandle);

    readline(FileHandle, CurrentLine);
    hread(CurrentLine, TempWord);
    Result(i)    := resize(TempWord, word_t'length);
  end loop;

  return Result;
end function;

A signal for the RAM is defined and initialized:

signal ram    : ram_t    := ocram_ReadMemFile(FILENAME);

This example should work in all simulators and in Xilinx ISE in synthesis, too. If you need a synthesizable example for Altera altsyncram, have a look at the complete files in our PoC-Library.

For example PoC.mem.ocram.tdp (true dual port memory).

\$\endgroup\$
  • \$\begingroup\$ I see, so the process that shall execute once only in the memory block architecture shall call this function, hmm.... \$\endgroup\$ – quantum231 Jul 18 '15 at 3:44
  • \$\begingroup\$ The architecture body is not shown in my example. Depending on your requirements you can implement ROMs, RAMs, dualport memories ... It's just a question on how to use the signal ram. The signal is initialized only once, before the simulation starts. \$\endgroup\$ – Paebbels Jul 18 '15 at 3:49
  • \$\begingroup\$ I have not seen the word "impure" used before. I have read about it. It seems that VHDL does not allow variables passed to it to be modified, thus it can only return values but not change values passed to it. If we want to change the values passed to it then we need to declare an impure function. What is not clear is since we are only reading a txt file and not modifying a file and it is declared and opened from within the function, why then do we need to have an 'impure function'? \$\endgroup\$ – quantum231 Jul 18 '15 at 16:29
  • \$\begingroup\$ @quantum231 Your comment on impure is correct. Yet I don't know why I added impure ... I'll check my code against different tools. \$\endgroup\$ – Paebbels Jul 19 '15 at 8:41
  • \$\begingroup\$ @quantum231 Update on your impure-question: Using file I/O violates the 'pure rule' for functions in VHDL. So impure is needed. \$\endgroup\$ – Paebbels Jul 19 '15 at 14:02
0
\$\begingroup\$

Previous answers require that the file is split into lines and that we know it's size. In this answer we can make the size of the memory dynamic by getting the file size first.

library IEEE;
use IEEE.STD_LOGIC_1164.all;        
use IEEE.STD_LOGIC_ARITH.all; 
use STD.TEXTIO.all;

entity MYROM is
--IO signals here
end entity;

architecture behaviour of MYROM is

type std_lv_array is array (natural range <>) of std_logic_vector(data'range);

impure function get_file_length(constant filename : string) return positive is
  type char_file_t is file of character;     
  file infile : char_file_t;
  variable c: character;
  variable res : integer := 0;
begin        
    file_open(infile, filename, read_mode);
    while not endfile (infile) loop
      read(infile, c);
      res := res + 1;
    end loop;
    file_close(infile);
    return res;
end function;


impure function get_data(constant filename : string) return std_lv_array is
  type char_file_t is file of character;     
  file infile : char_file_t;
  variable c: character;
  variable res : std_lv_array(0 to get_file_length(filename) - 1);  
  variable x : integer := 0;
begin
    file_open(infile, filename, read_mode);
    while not endfile (infile) loop
      read(infile, c);
      res(x) := std_logic_vector(conv_unsigned(character'pos(c),res(x)'length));
      x := x + 1;
    end loop; 
    file_close(infile);
    return res;
end function;

constant ROM : std_lv_array := get_data("romfile.bin");

begin
--Your code here
end architecture;
\$\endgroup\$
  • \$\begingroup\$ This does not answer the OP's questions. It's answering the comment of user 'Brian Jack'. \$\endgroup\$ – Paebbels Jul 6 '18 at 17:49

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.