Verilog读取HEX文件初始化ROM

女生的网名这么多〃 提交于 2020-03-23 20:48:26

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;

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!