verilog 二维的memory数据存储和读取

        在做有关矩阵运算时,需要我们将数据保存为二维数据的形式,如下

reg   [width:0]   mem [depth1:0] [depth2:0];

        这里的二维是对标matlab中的数据保存习惯,因为matlab中二维数组中的每个元素并不需要考虑位宽的问题,但是在verilog中需要考虑这一点。

        下面为将2048个数据保存为128*16的数据的例程,程序中memory定义的是128*128的大小,并不影响保存128*16的数据,程序分为数据存储和读取两部分,读取的部分在testbench中给出的激励是   读取第二行的128个数据。

        该行的数据,前两个为'hfaed18c8、'h07df180a     后两个数据为'hea71f2c2、'h07dfe7f5

`timescale 1ns / 1ps
//该模块实现多符号数据存储  并将每个符号读取进去FFT模块进行调制
module data_in_memory #(
    parameter NC_NUMBER              =    128,             //子载波数量
    parameter NS_NUMBER              =    128,              //符号数量
    parameter DATA_IMAGANDREAL_WIDTH =    32                //实数和虚数的总体位宽
)
(
    input sys_clk,
    input rst_n,
    //write
    input data_in_valid,                          //因为输入的特殊性,写使能信号一直有效 
                                                  //1024*128个长周期
    input [DATA_IMAGANDREAL_WIDTH-1:0] data_in,
    
    //read
    input        read_en,   //fft输出的valid信号    需要等到fft运算结束之后给出读使能信号
    input [$clog2(NC_NUMBER)-1:0] addr,            //读数据地址 fft输出的user信号
    input [$clog2(NC_NUMBER)-1:0] Ns_or_Nc_count,  //Ns_or_Nc_count 计数模块的输出
    
    output reg data_out_valid,                         //读出的数据有效标记
    output reg [DATA_IMAGANDREAL_WIDTH-1:0] data_out   //读出的数据
);

reg [$clog2(NS_NUMBER)-1:0] count_sys;                  //这是ram的地址索引和符号计数和子载 
                                                        //波计数有关联
reg [$clog2(NC_NUMBER)-1:0] count_carr;                 //子载波计数


//写入数据
//三维寄存器复位
reg [DATA_IMAGANDREAL_WIDTH-1:0] mem [NC_NUMBER-1:0][NS_NUMBER-1:0]; //二维还是三维??
integer i;                                           //子载波计数
integer j;                                           //符号计数
always@(posedge sys_clk or negedge rst_n) begin
    if(!rst_n) begin
        for (i=0;i<NC_NUMBER;i=i+1) begin            //赋初值
            for (j=0;j<NS_NUMBER;j=j+1) begin
                mem[i][j]<='d0;
            end
        end
    end
    else if(data_in_valid) begin
        mem[count_carr][count_sys]<=data_in;         //将每个接收数据存储
    end
end
//子载波计数count_carr
always@(posedge sys_clk or negedge rst_n) begin
    if(!rst_n)
        count_carr<='d0;
    else if(data_in_valid)
        count_carr<=count_carr+1'b1;              //子载波一直计数
    else
        count_carr<='d0;
end
//count_sys 符号计数
always@(posedge sys_clk or negedge rst_n) begin
    if(!rst_n)
        count_sys<='d0;
    else if(count_carr==NC_NUMBER-1)
        count_sys<=count_sys+1'b1;
    else if(!data_in_valid)                           
        count_sys<='d0;
    else
        count_sys<=count_sys;                  //子载波计数期间一直保存符号数的计数值 
end
///读出数据
always@(posedge sys_clk or negedge rst_n) begin
    if(!rst_n) begin
        data_out_valid<='d0;
        data_out<='d0;
    end
    else if(read_en) begin
        data_out_valid<=1'b1;
        data_out<=mem[addr][Ns_or_Nc_count];
    end
    else begin
        data_out_valid<='d0;
        data_out<='d0;
    end
end
endmodule

testbench

`timescale 1ns / 1ps
module test_data_in_memory();

parameter NC_NUMBER=128;
parameter NS_NUMBER=128;
parameter DATA_IMAGANDREAL_WIDTH=32;

reg sys_clk;
reg rst_n;

reg data_in_valid;
reg [31:0] data_in;

reg read_en;
reg [9:0] addr;
reg [9:0] Ns_or_Nc_count;

wire data_out_valid;
wire [31:0] data_out;

reg [31:0] echo_mem [2047:0];
initial begin
sys_clk='d0;
rst_n='d0;
$readmemb("D:/FPGA_one/rad_1024_128_Ranging_and_speed_v1/ranging_speed_echo.txt",echo_mem);
//这里的.txt文件保存了128*128长度的数据,为方便你测试,可以在matlab中生成,关于该文件的生成
//我将在后续中写出
#1000;
rst_n='b1;


#400000;
$stop;
end

always #10 sys_clk=~sys_clk;

data_in_memory #(
    .NC_NUMBER(NC_NUMBER),
    .NS_NUMBER(NS_NUMBER),
    .DATA_IMAGANDREAL_WIDTH(DATA_IMAGANDREAL_WIDTH)
)
u0 (
    .sys_clk(sys_clk),
    .rst_n(rst_n),
    
    .data_in_valid(data_in_valid),
    .data_in(data_in),
    
    .read_en(read_en),
    .addr(addr),
    .Ns_or_Nc_count(Ns_or_Nc_count),
    
    .data_out_valid(data_out_valid),
    .data_out(data_out)
);
reg [12:0] count;           //2^13 128*128
always@(posedge sys_clk or negedge rst_n) begin
    if(!rst_n)
        count<='d0;
    else if(count>='d2048)
        count<='dz;
    else
        count<=count+1'b1;
end
//valid
always@(posedge sys_clk or negedge rst_n) begin
    if(!rst_n) begin
        data_in<='d0;
        data_in_valid<='d0;
    end
    else if(count<=2047) begin
        data_in<=echo_mem[count]; //当前的count为0,但是输出数据与count=1对齐,需要注意,可 
                                  //通过将count打一拍来将count=0对齐输出数据
        data_in_valid<='d1;
    end
    else if(count==2048) begin     //因为只是测试,只取前16个128数据串即可
        data_in<=echo_mem[count];
        data_in_valid<='d0;
    end
    else begin
        data_in_valid<=data_in_valid;   //数据有效位,其实理解为数据使能也可以
        data_in<='d0;
    end
end
//read_en   Ns_or_Nc_count  addr
always@(posedge sys_clk or negedge rst_n) begin
    if(!rst_n) begin
        read_en<='d0;
        Ns_or_Nc_count<='d0;
        addr<='d0;
    end
    else if(count=='d255) begin  //取第二行的128个数据  在255计数处取值,输出数据在256处对齐
        read_en<='d1;
        Ns_or_Nc_count<='d1;     //0为第一行,1为第二行
        addr<=count-'d255;
    end
    else if(count=='d383) begin
        read_en<='d0;
        Ns_or_Nc_count<='d0;
        addr<='d0;
    end
    else begin
        read_en<=read_en;
        Ns_or_Nc_count<=Ns_or_Nc_count;
        addr<=addr+1'b1;
    end
end

endmodule

仿真结果如下:

         验证数据存入对不对,查看读取的数据对不对即可,于是放大读取的数据,查看前两个数据和后两个数据,data_out为输出数据:

         读取出的数据是正确的。

 

  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值