在做有关矩阵运算时,需要我们将数据保存为二维数据的形式,如下
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为输出数据:
读取出的数据是正确的。文章来源:https://www.toymoban.com/news/detail-606355.html
文章来源地址https://www.toymoban.com/news/detail-606355.html
到了这里,关于verilog 二维的memory数据存储和读取的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!