ILA
vivado工具集成了逻辑分析仪,ILA IP核用于替换外部的逻辑分析仪,添加探针来监控内部信号波形变化。
1)IP Catalog
2)搜索栏可搜索IP核,如创建FIFO、RAM等。
3)搜索并选择。
4)设置ILA各项参数。
5) 设置好IP核参数后点ok。
6)打开ila_0.evo。
7) 复制ila例化模板。
8)在设计文件中将IP核例化并连接,再生成比特流。
9)将比特流下载到板子中,点运行即可查看探针捕捉到的波形。
时钟
时钟IP核
RAM
Xilinx A7系列FPGA有140片block RAM每片内存为36k(bit),共4.9M。
双端口RAM可以写可以读(分别有读写时钟),但是要规定读写优先级。
单端口:只有一个端口,读写数据不能同时进行,共用数据通道。
伪双端口:拥有两个数据通道,一个用来写一个用来读。(常见)
真双端口:拥有两个数据通道,两个都可用来写/读。
创建RAM IP核:
创建RAM IP核的主设计代码ip_ram.v(例化了ram_rw 模块和ram IP 核blk_mem_gen_0):
blk_mem_gen_0来自IP核的.veo文件,直接例化即可。代码结构图如下:
`timescale 1ns / 1ps
module ip_ram(
input sys_clk,
input sys_rst_n
);
wire ram_en;
wire rw;
wire [4:0] ram_addr;
wire [7:0] ram_wr_data;
wire [7:0] douta;
ram_rw ram_rw_u(
.clk(sys_clk),
.rst_n(sys_rst_n),
.ram_en(ram_en),
.rw(rw),
.ram_addr(ram_addr),
.ram_wr_data(ram_wr_data)
);
blk_mem_gen_0 your_instance_name (
.clka(sys_clk), // input wire clka
.ena(ram_en), // input wire ena
.wea(rw), // input wire [0 : 0] wea
.addra(ram_addr), // input wire [4 : 0] addra
.dina(ram_wr_data), // input wire [7 : 0] dina
.douta(douta) // output wire [7 : 0] douta
);
endmodule
ram_rw.v作为读写模块驱动IP核,负责产生对ram IP核读/写所需的所有数据总线、地址总线以及控制信号,同时从ram IP读出的数据也被送进ram_rw 模块。
`timescale 1ns / 1ps
module ram_rw(
input clk,
input rst_n,
output reg ram_en,
output reg rw,
output reg[4:0] ram_addr,
output reg[7:0] ram_wr_data
);
reg [5:0] rw_cnt; //define a counter,write in [0:31],read in [32:63].
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
ram_en <= 1'b0;
end
else begin
ram_en <= 1'b1;
end
end
always @ (posedge clk or negedge rst_n) begin
if(~rst_n)
rw_cnt <= 6'd0;
else if(rw == 6'd63)
rw_cnt <= 6'd0;
else
rw_cnt <= rw_cnt +6'd1;
end
always @ (posedge clk or negedge rst_n) begin
if(~rst_n)
ram_wr_data <= 8'd0;
else if((rw_cnt <= 6'd31) && ram_en)// rw_cnt:0-31写操作。
ram_wr_data <= ram_wr_data + 8'd1;
else
ram_wr_data <= ram_wr_data;
end
//读写选择信号
always @(posedge clk or negedge rst_n) begin
if(~rst_n)
rw <= 1'b1;
else if(rw_cnt <= 6'd31)//rw_cnt:0-31写操作
rw <= 1'b1;
else
rw <= 1'b0;
end
always @(posedge clk or negedge rst_n) begin
if(~rst_n)
ram_addr <= 5'd0;
else
ram_addr <= rw_cnt[4:0];
end
endmodule
FIFO
搭建FIFO一般用Block Ram或Dram,Bram允许读写位宽不同。FIFO与FPGA内部RAM相比无外部读写地址线,采取顺序写入/读出数据方式。不能像RAM那样可由地址线决定读/写某个指定的地址。
1)创建工程后打开.v设计文件,并通过IP Catalog搜索FIFO,选择FIFO Generator。
2)要选择构成FIFO的适当RAM类型。
FIFO写操作:
`timescale 1ns / 1ps
//write->read->empty->write......
module fifo_wr(
input clk,
input rst_n,
input almost_empty,
input almost_full,
output reg fifo_wr_en,
output reg [7:0] fifo_wr_data
);
reg almost_empty_d0;
reg almost_empty_syn;
reg [3:0] dly_cnt;
reg [1:0] state;
wire syn;
assign syn = ~almost_empty_syn & almost_empty_d0;
// almost_empty拉高后的下一个周期syn拉高。
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
almost_empty_d0 <= 1'b0;
almost_empty_syn <= 1'b0;
end
else begin
almost_empty_d0 <= almost_empty;
// almost_empty延迟一个上升沿赋值给almost_empty_d0
almost_empty_syn <= almost_empty_d0;
// almost_empty_d0延迟一个上升沿赋值给almost_empty_syn
end
end
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
fifo_wr_en <= 1'b0;
fifo_wr_data <= 8'd0;
state <= 2'd0;
dly_cnt <= 4'b0;
//FIFO IP核不能立即就写入,所以要有一个延时,一般10拍就够。
end
else begin
//构造一个状态机,state有3个状态。
case(state)
//状态0:如果syn拉高,说明FIFO即将空了,该写了,于是跳到状态1;syn不拉高,则FIFO还未空,则不写。
2'd0:begin
if(syn) state <= 2'd1;
else state <= state;
end
//状态1:dly_cnt计满10个数后开始写。dly_cnt<10时一直+1;dly_cnt到10后,dly_cnt清零,跳到状态2,写使能fifo_wr_en拉高。
2'd1:begin
if(dly_cnt == 4'd10) begin
dly_cnt <= 4'b0;
state <= 2'd2;
fifo_wr_en <= 1'b1;
end
else begin
dly_cnt <= dly_cnt +1'b1;
end
end
//状态2:真正开始写了,FIFO一直写。如果写满almost_full拉高:写使能fifo_wr_en拉低,写数据fifo_wr_data归零,转向状态0。如果没写满:写使能继续拉高,写数据+1。(这里写数据根据项目自己确定写入的内容,可以是采集数据)
2'd2:begin
if(almost_full) begin
fifo_wr_en <= 1'b0;
fifo_wr_data <= 8'd0;
state <= 2'd0;
end
else begin
fifo_wr_en <= 1'b1;
fifo_wr_data <= fifo_wr_data + 1'b1;
end
end
default:state <= 2'd0;
endcase
end
end
endmodule
FIFO读操作:
`timescale 1ns / 1ps
//write->read->empty->write......
module fifo_rd(
input clk,
input rst_n,
input almost_empty,
input almost_full,
output reg fifo_rd_en
);
reg almost_full_d0;
reg almost_full_syn;
reg [3:0] dly_cnt;
reg [1:0] state;
wire syn;
assign syn = ~almost_full_syn & almost_full_d0;
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
almost_full_d0 <= 1'b0;
almost_full_syn <= 1'b0;
end
else begin
almost_full_d0 <= almost_full;
almost_full_syn <= almost_full_d0;
end
end
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
fifo_rd_en <= 1'b0;
state <= 2'd0;
dly_cnt <= 4'b0;
end
else begin
case(state)
2'd0:begin
if(syn) state <= 2'd1;
else state <= state;
end
2'd1:begin
if(dly_cnt == 4'd10) begin
dly_cnt <= 4'b0;
state <= 2'd2;
end
else begin
dly_cnt <= dly_cnt +1'b1;
end
end
2'd2:begin
if(almost_empty) begin
fifo_rd_en <= 1'b0;
state <= 2'd0;
end
else begin
fifo_rd_en <= 1'b1;
end
end
default:state <= 2'd0;
endcase
end
end
endmodule
完成管脚约束(IO Planning直接操作)
由于FIFO的读写操作无法通过板子看出来,所以添加ila探针:文章来源:https://www.toymoban.com/news/detail-419876.html
ila_0 your_instance_name (
.clk(sys_clk), // input wire clk
.probe0(fifo_wr_en), // input wire [0:0] probe0
.probe1(fifo_rd_en), // input wire [0:0] probe1
.probe2(empty), // input wire [0:0] probe2
.probe3(almost_empty), // input wire [0:0] probe3
.probe4(fifo_wr_data), // input wire [7:0] probe4
.probe5(dout), // input wire [7:0] probe5
.probe6(rd_data_count), // input wire [7:0] probe6
.probe7(wr_data_count), // input wire [7:0] probe7
.probe8(full), // input wire [0:0] probe8
.probe9(almost_full) // input wire [0:0] probe9
);
文章来源地址https://www.toymoban.com/news/detail-419876.html
到了这里,关于vivado IP核:ILA、时钟、RAM、FIFO的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!