新浪博客

quartus II存储器(RAM or ROM)的初始化文件(mif or hex)生成

2014-04-06 12:39阅读:
对于经常使用ROM或者RAM的开发者来说,对存储器进行初始化是一项繁琐的工作,如果只是几个还可以,几十个还能承受,几百个还不如花钱雇个人去写(但是如果钱比较多的话,我愿意去写呀,哈哈)。幸好大部分初始化数据是有规律的,可以通过某些程序来自动产生数据,那么是否也可以自动化产生我们想要的初始化文件呢。下面是通过搜集网络以及自己的体会,并且自己编程,总结的一些方法。初始文件在quartus ii 8.0中主要分为mif和hex两种,下面分别做介绍。
一、mif文件
(1) 第一种方法,就是在数据毫无规律的时候,只能通过手工输入,即采用quartus ii 8.0的输入初始化文件功能。
(2) 第二种方法就是在数据是通过某种方式产生,相互之间有规律,这时候我们可以通过编程的方式来产生mif文件。因为在fpga开发中特别是在数字信号处理开发时,Maltab是不可或缺的工具,往往数据都是由Matlab产生的,因此在这里介绍如何用Matlab产生mif文件。要想产生mif文件,需要对mif文件先做了解。
DEPTH = 1024; %%定义存储器深度,即存储器有多少个单元
WIDTH = 16; %%定义每个单元的位数
ADDRESS_RADIX = DEC; %%定义地址表达方式,是十进制
DATA_RADIX = HEX; %%定义数据表达方式,是十六进制
CONTENT %%表示下面的是存储器内容
BEGIN %%下一行表示开始
0: 0; %%冒号前表示地址,冒号后表示单元数据
1: 1;
2: 2;
.
.
.
END
从上面可以看出,mif文件相当简单,就是开头定义一些参数,然后就是写每个单元的数据,每个单元占一行,格式是“地址:数据;”。对此给出Matlab程序如下:
clear;clc;close all %%清空内存,显示屏和关闭所有图片
y = 0.5*sin(2*pi/100*[0:1023]); %%这是储存器的数据,这里以正弦
%%波为例,当然也可以通过其它方法产生的数据
N = length(y); %%数据的长度,即存储器深度
word_len = 16; %%每个单元的占据的位数,需自己设定。
y_quan =fi(y,1,word_len,word_len-1); %%matlab中产生的数据都是浮点%%类型,因此需要先转换为定点数,这里采用Matlab 2009a中的fi函数来构造,%%这句话表示产生的数据位长为word_len,小数部分占据word_len-1位的有符%%号定点数,并且以补码方式进行编码。详细见Matlab帮助
fid=fopen('sine.mif','w');%打开文件
str=strcat('DEPTH = ',num2str(N),';');%生成存储器深度字符串
fprintf(fid,str);%输出第一行
str=strcat('WIDTH =',num2str(word_len),';');%生成单元位数字符串
fprintf(fid,str);%输出第二行
fprintf(fid,'ADDRESS_RADIX = DEC;');%% 指定地址为十进制
fprintf(fid,'DATA_RADIX = HEX;'); %% 指定数据为十六进制
fprintf(fid,'CONTENT');
fprintf(fid,'BEGIN');
for ii=0:N-1
str=strcat(num2str(ii),':',hex(y_quan(ii+1)),'');%%输出的数%%据行字符串
fprintf(fid,' '); %%先输出空格
fprintf(fid,str);%%输出
end
fprintf(fid,'END');%%输出结尾
fclose(fid); %%关闭文件

二、hex文件
(1) 第一种方法跟mif的第一种方法一样,也是用quartus ii 8.0输入
(2) 第二种方法先用上述程序产生mif文件再用quartus ii 8.0转成hex文件
(3) 第三种方法用dspbuilder产生dspbuilderaltera公司专门为数字信号处理开发的工具它可以自动产生代码,这里不做详细介绍。在dspbuilder里面调用存储器模块,它的初始化数据可以选择来自matlab空间,在自动产生代码后,在代码堆里可以找到对应的hex。
(4) 上面第二、三种方法相对于第一种方法有了较大的改进,可以自动生成,不用在手工输入了。但是也有缺点,如果要生成多个hex文件,那么用第二种方法需要不停的调用quartus ii 8.0,而第三种方法需要不停的修改参数,尽管这些参数有一定的规律,还得需要自己改,就显得不太适合了。因此下面还是需要从编写代码的角度来完成自动化的工作,首先了解一下intel hex格式的文件,它是ascii代码文件,可以记事本打开,它的记录格式为:“:nnaaaattddddcc”, 每一行都是这种记录格式,其中每一组字母都是一个独立的域,都是一个十六进制数,每一个域至少由两个十六进制数组成,下面是对其描述:
(1) “:” 冒号 是每一条记录的开始
(2) “nn” 表示记录数据“dddd”的字节数目
(3) “aaaa” 表示地址,表示数据的起始地址,在这里是在存储器里的位置
(4) “tt”代表这条记录的属性,他有四种可能性
00--数据记录
01--文件结束记录
02--扩展段地址记录
04--扩展线性地址记录
在这里我们只用到前面两种属性,其它属性参见三级偏硬的书,或者查8086的内存读取部分,会了解这些含义。
(5) dddd”表示数据域,其中“dd”组成一个字节,一个记录可以有多个字节,字节数目必须和“nn”相等。
(6) cc”是校验和,是将本条记录冒号后的所有对相加(不包括校验对),将和除以256,取其余数,然后求出余数的补码就可以。
比如“03001053286c06
则“03+00+10+53+28+6c = FA,对“FA”求补码则为“06,即校验和。
最后文件的结尾永远是“:00000001FF
下面是Matlab的程序:
clear;clc;close all %%清空内存显示屏和关闭所有图片
y = 0.5*sin(2*pi/100*[0:1023]); %%这是储存器的数据这里以正弦
%%波为例,当然也可以通过其它方法产生的数据
N = length(y); %%数据的长度即存储器深度
word_len = 16; %%每个单元的占据的位数需自己设定。
len = ceil(word_len/8); %%转换成字节数。
y_quan =fi(y,1,word_len,word_len-1); %%matlab中产生的数据都是浮点%%类型因此需要先转换为定点数这里采用Matlab 2009a中的fi函数来构造%%这句话表示产生的数据位长为word_len,小数部分占据word_len-1位的有符%%号定点数并且以补码方式进行编码。详细见Matlab帮助
fid=fopen('sine.mif','w');%打开文件
for i=1:N
word_len = fi(len,0,8,0); %%即前面所说的nn
addr = fi(i,0,16,0); %%即前面所说的aaaa
%%下面计算校验和
temp=word_len+bitsliceget(addr,16,9)+bitsliceget(addr,8,1);
%%其中bitsliceget帮助参见matlab帮助
for jiaoye=1:len
temp=temp+bitsliceget(y_quan(i),jiaoye*8,jiaoye*8-7);
end
temp=bitsliceget(temp,8,1); %%取低8位,即相当于取模256
temp1=fi(256,0,9,0);
temp=temp1-temp;%%上面两步是取其补码,如果字长是n位,大小%%a,则其补码为2^n-a;
temp=bitsliceget(temp,8,1); %%重新取低8位,这里需要明白%Matlabfi构造的定点数性质
fprintf(fid,strcat(':',hex(word_len),hex(addr),'00',hex(data(len)),hex(temp),''));
end
fclose(fid); %%关闭文件

上面列举了各种方法,当然编程的方法是最有效的,当然其它方法在特定环境中有他的优势,不能一概而论,而且也有个人的喜好在里面,比如说在dspbuilder的方法,在进行数字信号处理开发时,他的优势就要比纯粹编程好,工具无缝衔接更好,毕竟是altera的工具。总之一句话,适合自己的才是最好的。

:10010000214601360121470136007EFE09D2190140 :100110002146017EB7C20001FF5F16002148011988 :10012000194E79234623965778239EDA3F01B2CAA7 :100130003F0156702B5E712B722B732146013421C7 :00000001FF
每一行代表对一个数据的描述,最后一行是结束。

可以看到每一条数据有6个颜色,每个颜色表示数据的一个区域:

表示开始码,固定为:
数据部分的字节数,数据部分两个16进制数代表一个字节
地址,固定4个16进制数,可见,可描述的数据是有限的
数据类型:00表示数据,01表示结尾,,,,
数据
校验,检验的方式是把前面的数据除了开始码部分的按每两个16进制一个字节进行相加,加大结果保留一个字节,并取反码。
知道了结果就用matlab编个程序吧:(参考:http://bbs.ednchina.com/BLOG_ARTICLE_2087845.HTM
clear all;
clc;
%描述一个16位位宽的数据
y=0:63;
N = length(y); %%数据的长度,即存储器深度。
word_len = 16; %%每个单元的占据的位数,需自己设定。
len = ceil(word_len/8); %%转换成字节数。
y_quan =fi(y,1,word_len,0); %%该函数详细见Matlab帮助
fid=fopen('dat.hex','w');%打开文件
temp1=fi(256,0,9,0);
word_len = fi(len,0,8,0); %%即前面所说的”nn”
for i=1:N
addr = fi(i-1,0,16,0); %%即前面所说的”aaaa”
%%下面计算校验和
temp=word_len+bitsliceget(addr,16,9)+bitsliceget(addr,8,1);
temp=temp+bitsliceget(y_quan(i),16,9)+bitsliceget(y_quan(i),8,1);
temp=bitsliceget(temp,8,1); %%取低8位,即相当于取模256
temp=temp1-temp;%%上面两步是取其补码,如果字长是n位,大小%%为a,则其补码为2^n-a;
temp=bitsliceget(temp,8,1); %%重新取低8位,这里需要明白%Matlab中fi构造的定点数性质
fprintf(fid,strcat(':',hex(word_len),hex(addr),'00',hex(bitsliceget(y_quan(i),16,9)),hex(bitsliceget(y_quan(i),8,1)),hex(temp),''));
end
fprintf(fid,':00000001ff');
fclose(fid); %%关闭文件
补充说明一下:

  • a = fi(v,s,w,f) 这个函数返回的是v的定点表示,s表示是否是有符合的,w表示字长,f表示小数点后的字长。

我的更多文章

下载客户端阅读体验更佳

APP专享