Verilog讀取HEX文件初始化ROM


ROM.v代碼

這個模塊設計的關鍵是在復位信號中執行初始化代碼,讀取指定位置的HEX文件中的數據初始化rom,然后在其他時鍾沿時刻輸出地址所指的數據。

//read hex file to initial ROM or RAM

module ROM(

    input clk,

    input rst_n,

    input[15:0] addr,

    output reg[7:0] q

    );

 

    parameter filename="F:/project/cpu/code/ModelSim/04_ROMInitTest/src/ROM.hex";

 

    reg[ 7:0] char_1st;

    reg[15:0] address; // Rom address

    reg[ 7:0] len; // bytes of one line in the hex file

    reg[ 7:0] dat;

    reg[7:0] sum; // intel hex file verification

    reg[640:1] errstr;

    reg[7:0] rom[0:4095];

    reg CanRead;

    integer i,fp,code;

 

    always@(posedge clk)

    if(!rst_n)begin

 

        char_1st = 0;

        address =0;

        len =0;

        dat =0;

        sum =0;

        CanRead =1;

 

        fp=$fopen(filename,"r");

 

        if(fp==0)begin

            $display($time,"ERROR: Hex File %s cann't be open!",filename);

            $stop; // stop when no such file

        end

        else begin

            $display($time,"Message: Hex File %s open succese!",filename);

        end

 

        if($ferror(fp,errstr))begin

            $display("%s",errstr);

            $display($time,"ERROR: Hex File %s error",filename);

            $stop;

        end

 

        while(CanRead)begin

            //first byte should be ":"

            char_1st=$fgetc(fp);

 

            if(char_1st=="\n")begin //if it is blank line read next char

                char_1st=$fgetc(fp);

            end

            else if(char_1st!=":")begin // every line begin with ":"

                //if one line is not start with ":" this file maybe not a hex file

                $display($time,"Error: The 1st char isn't [:]Hex File convert end! ");

                CanRead = 0;

            end

            else begin

                //the second and third byte means how many data in this line

                code=$fscanf(fp,"%2x",len);

 

                if(len==0)begin

                    $display($time,"Message:Initial Rom Finish!");

                    CanRead = 0;

                end

                else begin

 

                    sum=len;

                    code=$fscanf(fp,"%4x",address);

                    sum=sum+address;

                    sum=sum+(address>>8); // unsigned sum

                    code=$fscanf(fp,"%2x",dat); // data type

                    sum=sum+dat;

 

                    for(i=0;i<len;i=i+1)begin

                        code=$fscanf(fp,"%2x",dat);

                        sum=sum+dat;

                        rom[address]=dat; // ram read data from file

                        address=address+1;

                    end

 

                    code=$fscanf(fp,"%2x\n",dat); // check data

                    sum=sum+dat;

 

                    if(sum!=0)begin

                        $display("Error:verification code is not zero!");

                        CanRead = 0;

                    end

 

                end

 

            end

 

        end

    end

    else begin

        q<=rom[addr];

    end

 

endmodule

 

測試文件

ROM_t.v

 

 

module Rom_t;

 

    reg clk;

    reg rst_n;

    reg[15:0] addr;

    wire[7:0] q;

 

    ROMU_rom(

        clk,

        rst_n,

        addr,

        q

    );

 

    always #1 clk=~clk;

 

    initial begin

        clk<=0;

        rst_n<=1;

        #5 rst_n<=0;

        #5 rst_n<=1;

    end

 

    always@(posedge clk)

    if(!rst_n)begin

        addr<=0;

    end

    else begin

        addr<=addr+1;

 

    end

 

endmodule

 

 

測試所用HEX是Keil編譯一段C語言代碼后生成的十六進制文件。用STC-ISP打開如下圖(可以用任意一個HEX文件繼續后續實驗)

 

 

以上3個文件(ROM.v,Rom_t.v,ROM.hex)放在\04_ROMInitTest\src目錄下,代碼中會從這個目錄打開ROM.hex文件。

 

Modelsim中啟動仿真,結果如下圖

 

 

控制台輸出如下內容:

上面的時序圖中可見clk的上升沿中有2次都檢測到rst_n為0,所以上面的初始化代碼會執行2次。

 

附上網上一段關於HEX和mif文件相關的資料:

 

hex文件又叫intel hex文件

Intel HEX由任意數量的十六進制記錄組成。每個記錄包含5個域,它們按以下格式排列:
:llaaaatt[dd...]cc
每一組字母對應一個不同的域,每一個字母對應一個十六進制編碼的數字。每一個域由至少兩個十六進制編碼數字組成,

它們構成一個字節,就像以下描述的那樣:
: 每個Intel HEX記錄都由冒號開頭.
ll 是數據長度域,它代表記錄當中數據字節(dd)的數量.
aaaa 是地址域,它代表記錄當中數據的起始地址.
tt 是代表HEX記錄類型的域,它可能是以下數據當中的一個:
00 – 數據記錄
01 – 文件結束記錄
02 – 擴展段地址記錄
04 – 擴展線性地址記錄
dd 是數據域,它代表一個字節的數據.一個記錄可以有許多數據字節.記錄當中數據字節的數量必須和數據長度域(ll)中指

定的數字相符.
cc 是校驗和域,它表示這個記錄的校驗和.校驗和的計算是通過將記錄當中所有十六進制編碼數字對的值相加,以256為模

進行以下補足.

數據記錄
Intel HEX文件由任意數量以回車換行符結束的數據記錄組成.數據記錄外觀如下:
:10246200464C5549442050524F46494C4500464C33
其中:
10 是這個記錄當中數據字節的數量.
2462 是數據將被下載到存儲器當中的地址.
00 是記錄類型(數據記錄)
464C…464C是數據.
33 是這個記錄的校驗和.

mif文件比起hex文件就要"單純"許多 因為她沒有最后的坑爹的校驗和 所以生成起來比較容易

mif文件的格式范例如下

WIDTH=128;
DEPTH=4096;

ADDRESS_RADIX=HEX;                                                                            //十進制為DEC 
DATA_RADIX=HEX;                                                                                   //二進制為BIN

CONTENT BEGIN
0000 : 000000000000000000000000FFFFFFF0;
0001 : 000000000000000000000000FFFFFFF1;
0002 : 000000000000000000000000FFFFFFF2;
0003 : 000000000000000000000000FFFFFFF3;

.............................................................................

..............................................................................

END;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM