Search code examples
vhdlrammodelsimquartus

VHDL Pre-loading RAM Memory with MIF File


I am trying to implement memory in VHDL and when testing it on the DE2 board I want to preload the memory with generated values. I first tried doing this by reading from a text file, but that did not work because one cannot load a text file onto the FPGA board. So I turned to mif files. However, I do not know how to get vhdl/quartus ii to associate the MIF file I generated with the RAM I created.

I also tried using a 1-port RAM LPM, but because it clocks the reading as well as the writing and this causes it to not provide the data fast enough to be useful.

Below is the code for the RAM I created:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;

entity instruction_memory is
    port (
        input_address : in std_logic_vector(31 downto 0);
        opcode : out std_logic_vector(31 downto 0)
    );
end instruction_memory;

architecture archInstruction_Memory of instruction_memory is
    subtype word_t  is std_logic_vector(31 downto 0);
    type    ram_t   is array(0 to 4095) of Reichman_word_t;

    impure function ReadMemFile(FileName : STRING) return ram_t is
        file FileHandle       : TEXT open READ_MODE is FileName;
        variable CurrentLine  : LINE;
        variable TempWord     : bit_vector(31 downto 0);
        variable Result       : ram_t    := (others => (others => '0'));

        begin
           for i in 0 to 4095 loop
                exit when endfile(FileHandle);
                readline(FileHandle, CurrentLine);
                read(CurrentLine, TempWord);
                Result(i) := to_stdlogicvector(TempWord);
            end loop;

            return Result;
        end function;

        signal ram    : ram_t    := ReadMemFile("instructions_memory.txt");
        attribute ram_init_file : string;
        attribute ram_init_file of ram : signal is "instructions_memory.mif";


begin 
    opcode <= ram(to_integer(unsigned(input_address(31 downto 0))));
end archInstruction_Memory;

How can I get it preload the data in the .mif file so when I test it on the DE2 board it shows that it uses those values?


Solution

  • I'm using a tcl script to translate binary data (code) into a VHDL constant that can be used to generate a ROM:

    package require cmdline
    
    post_message "embed_m68k.tcl"
    
    exec /bin/bash -c "(cd m68k; make)"
    set binfile m68k/simple.bin
    set fp [open $binfile r]
    fconfigure $fp -translation binary
    set bindata [read $fp]
    close $fp
    
    set filename simple.vhd
    
    set date [clock format [clock seconds] -format { %a, %Y-%m-%d, %H:%M }]
    set file [open $filename w]
    set script [info script]
    
    puts $file "library ieee;"
    puts $file "use ieee.std_logic_1164.all;"
    puts $file ""
    puts $file "    -- VHDL representation of $binfile"
    puts $file "    -- generated by $script on $date"
    puts $file "    -- m68k executable as preloaded RAM contents"
    puts $file ""
    puts $file "package m68k_binary is"
    puts $file "    subtype ubyte is std_logic_vector(7 downto 0);"
    puts $file "    type ubyte_array is array (natural range <>) of ubyte;"
    puts $file ""
    puts $file "    constant m68k_binary    : ubyte_array :="
    puts $file "    ("
    puts -nonewline $file "        "
    set len [string length $bindata]
    for {set i 0} {$i < $len} {incr i} {
        set char [string index $bindata $i]
        binary scan $char H2 byte
        puts -nonewline $file "x\""
        puts -nonewline $file $byte
        puts -nonewline $file "\""
        if { ! ([expr $i + 1] == $len) } {
            puts -nonewline $file ", "
        }
        if { [expr ($i + 1) % 8] == 0 } {
            puts $file ""
            puts -nonewline $file "        "
        }
    }
    puts $file ""
    puts $file "    );"
    puts $file "end package m68k_binary;"
    close $file
    

    You can easily include the script into your Quartus workflow using the PRE_FLOW_SCRIPT_FILE variable in your .qsf:

    set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:precmd.tcl"
    

    The PRE_FLOW_SCRIPT_FILE will then automatically be executed at the beginning of the synthesis process. Just include the generated .vhd file into your project.