我是靠谱客的博主 爱撒娇服饰,这篇文章主要介绍ISE使用中RAM IP核配置及ram测试(两种测试)分类定制过程及说明ram测试(1)ram测试(2)Aram测试(2)B,现在分享给大家,希望可以做个参考。

简单总结ISE中RAM的ip核配置过程以及相关的端口。

分类

ram分为分布式ram(distributed ram)以及块ram(block ram)
前者是自己用寄存器搭建的,这里理解可以转至Vivado使用技巧(27):RAM编写技巧
简单理解块ram就是自己用寄存器写出来的储存单元,仅仅用于储存比较少量的数据。优点是dram不需要时钟线来控制,可以直接用组合逻辑进行控制。bram是fpga中定制的ram资源,控制起来需要用时钟线,以及其他UI界面设定的io接口进行配置。

定制过程及说明

  1. 首先进入页面,打开进行选择要生成的ip核
  2. 选择你要定制的类型
    在这里插入图片描述
    可以选择的类型有如下五个,其中两种是ROM,三种是RAM。这里只总结RAM,ROM前面有进行简单的总结,后面会结合所学的,对这些全部进行注意点的总结。接下来是几种RAM的简介。
    在这里插入图片描述

single - port RAM

简单单口RAM
在这里插入图片描述

端口说明

ADDRA 为地址线
DINA 为数据输入端
ENA 为可选端口,在其为高电平时,才使能。
WEA 为写使能“当其为高电平是,DINA数据才会被写入对应的地址,这里[0:0],仿真的时候会发现,这里的数据不同于时钟线,而是数据。”
DOUTA 为A输出端
CLKA 为时钟线

Simple Dual Port Ram

在这里插入图片描述
这里只是多出来了个B端口,其中B用来读数据。
这里就会遇到一个问题,当同时写入数据和读出数据的时候该怎么进行选择呢,这里会有用户自行设定,会在接下来的页面中进行介绍。(这里可以分为三种模式)

True Dual-port RAM

在这里插入图片描述
图中上边的端口A和下边的端口B都支持读写操作,WEA、WEB信号为高时进行写操作,低为读操作。同时它支持两个端口读写操作的任何组合:两个同时读操作、两个端口同时写操作或者在两个不同的时钟下一个端口执行写操作,另一个端口执行读操作。

同时这里有一个选择框,问是否使用同一个时钟(CLKA,CLKB)
在这里插入图片描述

  1. 数据端口配置
    这里可以配置写入的宽度和深度。在这里插入图片描述
    同时可以尽行不同宽度的读取。就是说写入的宽度不同于读取的宽度。系统会对深度进行自动设定。
    在这里插入图片描述

当选择真正双口ram的实时候,会出现这里的三个设计端口。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 其他配置
    后面还有几页,这里笔者能力有限,以后进行补充。

ram测试(1)

代码主要是描述了读写时间的控制,然后对写入的内容进行控制。这里测试代码来源于开拓者资料(我买的黑金板子,那个资料,,无语-----)
下是测试结果,可以看到,ram读出的数据需要延时一个时钟周期。就是说,在读地址位为1的时候,它读出的数据其实是地址0里边的数据。
在这里插入图片描述
(解决输出延时一个周期的方法是,让读地址提前一个时钟周期,读地址去读,读地址的延时作为数据的观测)如下图
在这里插入图片描述

代码书写

这里的读数据使能我没有用,具体代码如下

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
module ip_ram( input sys_clk, input sys_rst_n ); wire [0:0] ram_wr_en ; //ram写使能 wire ram_rd_en ; //ram读使能 wire [4:0] ram_addr ; //ram读写地址 wire [7:0] ram_wr_data; //ram写数据 wire [7:0] ram_rd_data; //ram读数据 ram_rw A ( .clk(sys_clk), .rst_n(sys_rst_n), .ram_rd_data(ram_rd_data), .ram_wr_en(ram_wr_en), .ram_rd_en(ram_rd_en), .ram_addr(ram_addr), .ram_wr_data(ram_wr_data) ); ram_test B ( .clka(sys_clk), // input clka .wea(ram_wr_en), // input [0 : 0] wea .addra(ram_addr), // input [4 : 0] addra .dina(ram_wr_data), // input [7 : 0] dina .clkb(sys_clk), // input clkb .addrb(ram_addr), // input [4 : 0] addrb .doutb(ram_rd_data) // output [7 : 0] doutb ); endmodule module ram_rw( clk,rst_n,ram_rd_data, ram_wr_en,ram_rd_en,ram_addr,ram_wr_data ); input clk ; //系统时钟 input rst_n ; //复位信号 input [7:0] ram_rd_data ; //ram读数据 output [0:0] ram_wr_en ; //写使能信号 output ram_rd_en ; //读使能信号 output reg [4:0] ram_addr ; //ram写地址 output reg [7:0] ram_wr_data ; //ram写数据 reg [5:0] rw_cnt ; //读写控制计数器 //数据计数在0-31之内,ram写使能为高电平 assign ram_wr_en = ((rw_cnt >= 6'd0) && (rw_cnt <= 6'd31)) ? 1'b1 : 1'b0; //数据计数在32-63之内,ram读使能为高电平 assign ram_rd_en = ((rw_cnt >= 6'd32) && (rw_cnt <= 6'd62)) ? 1'b1 : 1'b0; always @ (posedge clk or negedge rst_n) begin if(!rst_n) rw_cnt <= 6'd0; else if(rw_cnt == 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'd0) && (rw_cnt <= 6'd31)) ram_wr_data <= ram_wr_data + 8'b1; else ram_wr_data <= 8'd0; end //读地址信号控制,读地址一直循环在所有地址之间 always @ (posedge clk or negedge rst_n) begin if(!rst_n) ram_addr <= 5'd0; else if(ram_addr == 5'd31) ram_addr <= 5'd0; else ram_addr <= ram_addr + 5'd1; end endmodule

ram测试(2)A

测试八位写入,十六位读出,这里只需要控制写入数据,读取数据是只需要控制地址位即可。

在这里插入图片描述
这里只有一个数据有问题,就是在ram里的第15个数据,也就是对应的30和31次写入的数据不对,同时可以看出,读出数据的时候也是要延时一个时钟周期。而且这里读出的数据,例如01,写入0f 02 写入05
这样读出的第一位数据是050f
换了一个顺序,将后写入的数据作为高位?!
所以在次基础上,增加一个测试,见ram测试(2)B

代码书写

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
module ip_ram2(sys_clk,sys_rst_n ); input sys_clk ; input sys_rst_n ; reg [0:0] wea; reg [4:0] wr_addr; reg [3:0] rd_addr; wire [7:0] wr_data; reg [0:0] cnt_en ; //写地址,写入当有wea信号来的时候,地址位+1 always @ (posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) wr_addr <= 5'd0; else if(wr_addr == 5'd31) wr_addr <= 5'd0; else if(wea) wr_addr <= wr_addr + 1'b1; else wr_addr <= wr_addr; end //读地址控制 always @ (posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) rd_addr <= 4'd0; else rd_addr <= rd_addr + 4'd1; end //控制写使能信号 always @ (posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) wea <= 1'b0; else if(cnt_en == 1'b1) wea <= 1'b1; else wea <= 1'b0; end //cnt_en计数 always @ (posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) cnt_en <= 1'b0; else if(cnt_en == 1'b1) cnt_en <= 1'b0; else cnt_en <= 1'b1; end assign wr_data = ( wr_addr%2 ) ? 8'h5 : 8'hf; ram_test2 A ( .clka(sys_clk), // input clka .wea(wea), // input [0 : 0] wea .addra(wr_addr), // input [4 : 0] addra .dina(wr_data), // input [7 : 0] dina .clkb(sys_clk), // input clkb .addrb(rd_addr), // input [3 : 0] addrb .doutb(doutb) // output [15 : 0] doutb ); endmodule

ram测试(2)B

这里对其初始化,直接读出数据。
在这里插入图片描述在这里插入图片描述
这里可以看出,确实是8位写入,16位读出的时候,第0位读出的数据是1100
写入时候,0写入的时候,写入的是00,1写入的时候,写的数据时11
读出的时候。可以看出其变换(同样延时一个时钟周期读出数据)

代码书写

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
module ip_ram3( clk ); input clk; reg [1:0] addrb = 2'd0; always @ (posedge clk ) begin addrb <= addrb + 1'b1; end ram_dual_test A ( .clka(clk), // input clka .wea(wea), // input [0 : 0] wea .addra(addra), // input [2 : 0] addra .dina(dina), // input [7 : 0] dina .clkb(clk), // input clkb .addrb(addrb), // input [1 : 0] addrb .doutb(doutb) // output [15 : 0] doutb ); endmodule

以上就完成了简单的配置以及简单的测试。当然,也可以对其进行初始化。类似rom操作。
参考博文:
双口RAM及Vivado RAM IP核的使用
Vivado使用技巧(27):RAM编写技巧
感谢~

最后

以上就是爱撒娇服饰最近收集整理的关于ISE使用中RAM IP核配置及ram测试(两种测试)分类定制过程及说明ram测试(1)ram测试(2)Aram测试(2)B的全部内容,更多相关ISE使用中RAM内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(86)

评论列表共有 0 条评论

立即
投稿
返回
顶部