使用matlab生成正弦波、爱心波以及单精度浮点数转二进制的coe文件(存储深度与数据位宽可调)

使用matlab生成正弦波、爱心波以及单精度浮点数转二进制的coe文件(存储深度与数据位宽可调)


前言

  某个周一晚上和队友搞那个正弦波的coe文件搞到了12点多,在网上也没找到合适的,于是下定决心自己写一个,在此记录一下,顺带发了个生成爱心波和浮点数的coe文件。本文用matlab生成正弦波、爱心波以及单精度浮点数转二进制的coe文件(存储深度与数据位宽可调)。


提示:以下是本篇文章正文内容,均为作者本人原创,写文章实属不易,希望对大家有帮助。

一、coe文件的格式

在ISE中,ROM或者RAM的IP核生成需要初始化文件。

格式如下:

memory_initialization_radix = 2;
memory_initialization_vector = 
111111011011,
111111100111,
111111110100;

        第一行代码告诉vivado我们的数据是以二进制形式存储于coe文件中的,这里可以改成其他任何你想写入的进制。

        第二行的等号后面就是存储的二进制数据。注意一下格式,前面的数据后面以逗号结尾,最后一个数据要用分号结尾。

二、二进制数据的表示格式

        其实写入coe文件的数据为了方便可以直接写整数,就不用考虑二进制的原码、反码、补码的转换,但由于我之前把浮点数写入coe文件的时候用的二进制格式,因为写浮点数到coe文件也只能二进制(浮点数如何用二进制表示此处就不赘述了),所以这个正弦波以及爱心波都是以二进制的格式写入到coe文件中的。

        由于是二进制数据,那么此处有必要复习一下二进制的表示方法,因为那个周一晚上和队友搞了很久没搞出来就是因为当时对这个格式有点陌生了,所以编程一直出了点bug。

        二进制有三种形式:原码、反码、补码

        正数的原码、反码、补码均相同,所以不用过多纠结。就比如说+6以4位二进制数表示就为0_110,第一个0为符号位,符号位的规则是0正1负。那么+6的原码、反码、补码均为0_110。

        我们需要注意的是负数,负数的原码除了符号位其他与其对应的正数的原码一样,比如-6以4位二进制数表示,那么它的原码就为1_110。负数的反码是对原码除符号位进行取反,比如-6以4位二进制数表示,那么它的反码就为1_001。负数的补码是在反码的基础上加1,比如-6以4位二进制数表示,那么它的补码就为1_010。

        需要注意的是计算机中不管正数还是负数都是以补码的形式表示的,所以最终计算机中+6以4位二进制数表示就为0_110,-6以4位二进制数表示就为1_010。

三、正弦波

1.MATLAB代码

clear all;
close all;
depth=2^12;  %存储器的深度
width=12;    %width为二进制数据位宽
N=0:depth-1;
y_write=zeros(depth,1);
y=ceil((2^(width-1)-1)*sin(2*pi *N/depth)); %正弦波
 plot(y,'m','LineWidth',2);

fid=fopen('sin.coe','w');
fprintf(fid,'memory_initialization_radix=2;\n');
fprintf(fid,'memory_initialization_vector=\n'); 
for i=1:depth
    if (y(1,i)<0)   
        y_write(i,1)=y(1,i)+2^(width-1);%负数用补码表示
    else
        y_write(i,1)=y(1,i);
    end
end
for i=1:depth
    if (y(1,i)<0)   
        y_bin=dec2bin(y_write(i,1),width-1);
        if(i == depth)
            fprintf(fid,'%c','1'); 
            for j=1:width-2
                fprintf(fid,'%c',y_bin(j));
            end
            fprintf(fid,'%c;',y_bin(width-1));
        else
            fprintf(fid,'%c','1'); 
            for j=1:width-2
                fprintf(fid,'%c',y_bin(j));
            end
            fprintf(fid,'%c,\n',y_bin(width-1));
        end
    else
        y_bin=dec2bin(y_write(i,1),width-1);
        if(i == depth)
            fprintf(fid,'%c','0'); 
            for j=1:width-2
                fprintf(fid,'%c',y_bin(j));
            end
            fprintf(fid,'%c;',y_bin(width-1));        
        else
            fprintf(fid,'%c','0'); 
            for j=1:width-2
                fprintf(fid,'%c',y_bin(j));
            end
            fprintf(fid,'%c,\n',y_bin(width-1));  
        end
    end
end
fclose(fid);%关闭文件 

2.vivado代码

用的是ROM IP核。

顶层代码:

`timescale 1ns / 1ps
//
// Company: cq university
// Engineer: clg
// Create Date: 2022/10/25 15:37:36
// Design Name: 
// Module Name: rom_test
// Project Name: 
// Target Devices: 
// Tool Versions: 2017.4
// Description: 
// Dependencies: 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//

module rom_test(
input clk,
output [11:0] dout
    );

reg [11:0] address=0;
always @(posedge clk) begin
    address<=address+1;
end
rom_ip u1_rom_ip (
  .clka(clk),    // input wire clka
  .addra(address),  // input wire [11 : 0] addra
  .douta(dout)  // output wire [11 : 0] douta
);

endmodule

仿真代码:

`timescale 1ns / 1ps
//
// Company: cq university
// Engineer: clg
// Create Date: 2022/10/25 15:37:59
// Design Name: 
// Module Name: rom_test_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 2017.4
// Description: 
// Dependencies: 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
module rom_test_tb;
// rom_test Parameters
parameter PERIOD  = 2;
// rom_test Inputs
reg   clk                                  = 0 ;
// rom_test Outputs
wire  [11:0]  dout                         ;

initial
begin
    forever #(PERIOD/2)  clk=~clk;
end

rom_test  u_rom_test (
    .clk                     ( clk          ),
    .dout                    ( dout  [11:0] )
);

endmodule

结果:

vivado仿真结果出来后注意先设置数据格式

 设置完了就能看见如下的正弦波:

四、爱心波

1.MATLAB代码

clear all;
close all;
depth=2^12;  %存储器的深度
width=12;    %width为二进制数据位宽
N=0:depth-1;
y_write=zeros(depth,1);
%爱心波
a=10;
b5=1:depth;
y = real(round((2^(width-2)/4-4)*(abs((b5-depth/2)/1000).^(2/3)+(0.9*sqrt((3.3-((b5-depth/2)/1000).^2))).*sin(a*pi*((b5-depth/2))/1000)+1.8)));
plot(y,'m','LineWidth',2);

fid=fopen('sin.coe','w');
fprintf(fid,'memory_initialization_radix=2;\n');
fprintf(fid,'memory_initialization_vector=\n'); 
for i=1:depth
    if (y(1,i)<0)   
        y_write(i,1)=y(1,i)+2^(width-1);%负数用补码表示
    else
        y_write(i,1)=y(1,i);
    end
end
for i=1:depth
    if (y(1,i)<0)   
        y_bin=dec2bin(y_write(i,1),width-1);
        if(i == depth)
            fprintf(fid,'%c','1'); 
            for j=1:width-2
                fprintf(fid,'%c',y_bin(j));
            end
            fprintf(fid,'%c;',y_bin(width-1));
        else
            fprintf(fid,'%c','1'); 
            for j=1:width-2
                fprintf(fid,'%c',y_bin(j));
            end
            fprintf(fid,'%c,\n',y_bin(width-1));
        end
    else
        y_bin=dec2bin(y_write(i,1),width-1);
        if(i == depth)
            fprintf(fid,'%c','0'); 
            for j=1:width-2
                fprintf(fid,'%c',y_bin(j));
            end
            fprintf(fid,'%c;',y_bin(width-1));        
        else
            fprintf(fid,'%c','0'); 
            for j=1:width-2
                fprintf(fid,'%c',y_bin(j));
            end
            fprintf(fid,'%c,\n',y_bin(width-1));  
        end
    end
end
fclose(fid);%关闭文件 

 2.vivado代码

        这个代码同正弦波那里的vivado代码,只需要将IP核当中的coe文件数据改成存储爱心波的数据就可以了。

 五、单精度浮点数转二进制的coe数据的MATLAB代码

 fid=fopen('single.coe','w');
 fprintf(fid,'memory_initialization_radix=2;\n');
 fprintf(fid,'memory_initialization_vector=\n');
Y=[1.2 2.2;2.3 -5.4];%要写的浮点数数据放置于矩阵中
N=2;%Y矩阵的行数
K=2;%Y矩阵的列数
for mm=1:N
    for nn=1:K
        for pp=1:32
           q=quantizer('single');
           bin=num2bin(q,Y(mm,nn));
           bin1=bin(pp);
           if(bin1=='1')
               bin2=1;
           else
               bin2=0;
           end
           fprintf(fid,'%d',bin2);
        end
    fprintf(fid,',\n');
    end
end
fprintf(fid,';');
fclose(fid);

写完之后如下:

         注意这个格式有一点点BUG,程序中我也没有优化了,写完之后需要人为将第倒数第二行行末尾的逗号改为倒数第一行的分号,改了之后才符合coe文件的格式,才能放到IP核中去。


总结

        以上就是今天要分享的全部内容,希望对大家有所帮助。

猜你喜欢

转载自blog.csdn.net/m0_66360845/article/details/127530448