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产生,dspbuilder是altera公司专门为数字信号处理开发的工具,它可以自动产生代码,这里不做详细介绍。在dspbuilder里面调用存储器模块,它的初始化数据可以选择来自matlab空间,在自动产生代码后,在代码堆里可以找到对应的hex。
(4)
上面第二、三种方法相对于第一种方法有了较大的改进,可以自动生成,不用在手工输入了。但是也有缺点,如果要生成多个hex文件,那么用第二种方法需要不停的调用quartus
ii
8.0,而第三种方法需要不停的修改参数,尽管这些参数有一定的规律,还得需要自己改,就显得不太适合了。因此下面还是需要从编写代码的角度来完成自动化的工作,首先了解一下intel
hex格式的文件,它是ascii代码文件,可以记事本打开,它的记录格式为:“:nnaaaattdd…ddcc”,
每一行都是这种记录格式,其中每一组字母都是一个独立的域,都是一个十六进制数,每一个域至少由两个十六进制数组成,下面是对其描述:
(1) “:”
冒号
是每一条记录的开始
(2) “nn”
表示记录数据“dd…dd”的字节数目
(3) “aaaa”
表示地址,表示数据的起始地址,在这里是在存储器里的位置
(4)
“tt”代表这条记录的属性,他有四种可能性
00--数据记录
01--文件结束记录
02--扩展段地址记录
04--扩展线性地址记录
在这里我们只用到前面两种属性,其它属性参见三级偏硬的书,或者查8086的内存读取部分,会了解这些含义。
(5)
“dd…dd”表示数据域,其中“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位,这里需要明白%Matlab中fi构造的定点数性质
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表示小数点后的字长。