胡叨叨教你实战RAM

RAM种类

Xilinx的RAM有三种类型:单口RAM、简单双口RAM、真双口RAM。

单口RAM

单口RAM的读和写均使用同一个端口,同一时间只能进行一种操作。

简单双口RAM

简单双口RAM具有两个通道,分别为写通道和读通道,并且每个通道只能完成一种操作。

真双口RAM

真双口RAM具有两个通道,并且这两个通道均可以实现读和写操作。

简单双口RAM实战

本实战例化4种不同位宽转换的RAM,通过仿真查看各种结果。

写操作

四个RAM的写操作使用同一种。

在ena和wea有效时,写入10个数据。

实现代码

always @(posedge i_clk ) begin
    if (addra == 'd10 - 1)
        ena <= 1'b0 ;
    else if (pos_ram_wr_en)
        ena <= 1'b1 ;
end

always @(posedge i_clk ) begin
    if (ena)
        addra <= addra + 1'b1 ;
    else 
        addra <= 'd0 ;
end

always @(posedge i_clk ) begin
    if (ena)
        dina <= dina + 32'h04040404 ;
    else 
        dina <= 32'h00010203 ;
end

仿真结果

由仿真可以看出,在ena有效时,地址从0开始增加,数据开始写入到RAM中。

虽然在ena无效后,递增和数据均增加了一个,但是由于ena的无效,多出来的地址和数据也不会写入到RAM中。

写入数据长度

由于在ena拉低后,地址还会增加一个,可以利用此特性来寄存写入的数据长度,用于判断读出的数据长度。

将ena打一拍,用于取其下降沿,利用此下降沿信号寄存数据长度。

需要注意:在使用此数据长度时,需要进行-1处理。

实现代码

always @(posedge i_clk ) begin
    ena_1d <= ena ;
end

assign neg_ena = !ena & ena_1d ;

always @(posedge i_clk ) begin
    if (neg_ena)
        num_data <= addra ;
end

仿真结果

32i-8o读操作

此RAM的输入是32bit位宽,输出是8bit位宽,实现了位宽的转换。

在此需要注意,由于写入的位宽和读出的位宽不一致,相应的写入的地址和读出的地址也不同。在此RAM中,读出地址的长度是写入地址长度的4倍。

需要注意:读出的数据与写入的数据的大小端是相反的。

也就是说,如果想按照正确的顺序将数据读出来,需要提前将写入的数据进行大端转小端。

读出的数据在地址有效的下一个时钟周期输出。

实现代码

always @(posedge i_clk ) begin 
    if (ram1_addrb == (num_data<<2) - 1)
        ram1_enb <= 1'b0 ;
    else if (neg_ena)
        ram1_enb <= 1'b1 ;
end

always @(posedge i_clk ) begin
    if (ram1_addrb == (num_data<<2) - 1)
        ram1_addrb <= 1'b0 ;
    else if (ram1_enb)
        ram1_addrb <= ram1_addrb + 1'b1 ;
end

仿真结果

32i-16o读操作

此RAM的输入是32bit位宽,输出是16bit位宽,实现了位宽的转换。

在此需要注意,由于写入的位宽和读出的位宽不一致,相应的写入的地址和读出的地址也不同。在此RAM中,读出地址的长度是写入地址长度的2倍。

需要注意:读出的数据与写入的数据的大小端是相反的。

也就是说,如果想按照正确的顺序将数据读出来,需要提前将写入的数据进行大端转小端。

读出的数据在地址有效的下一个时钟周期输出。

实现代码

always @(posedge i_clk ) begin 
    if (ram2_addrb == (num_data<<1) - 1)
        ram2_enb <= 1'b0 ;
    else if (neg_ena)
        ram2_enb <= 1'b1 ;
end

always @(posedge i_clk ) begin
    if (ram2_addrb == (num_data<<1) - 1)
        ram2_addrb <= 1'b0 ;
    else if (ram2_enb)
        ram2_addrb <= ram2_addrb + 1'b1 ;
end

仿真结果

32i-32o读操作

此RAM的输入是32bit位宽,输出是32bit位宽,实现了数据缓存。

需要注意:读出的数据与写入的数据一致。

读出的数据在地址有效的下一个时钟周期输出。

实现代码

always @(posedge i_clk ) begin 
    if (ram3_addrb == (num_data<<0) - 1)
        ram3_enb <= 1'b0 ;
    else if (neg_ena)
        ram3_enb <= 1'b1 ;
end

always @(posedge i_clk ) begin
    if (ram3_addrb == (num_data<<0) - 1)
        ram3_addrb <= 1'b0 ;
    else if (ram3_enb)
        ram3_addrb <= ram3_addrb + 1'b1 ;
end

仿真结果

32i-64o读操作

此RAM的输入是32bit位宽,输出是64bit位宽,实现了位宽的转换。

这种操作就有意思了,读出的数据都错乱了。

仿真结果

结论

  1. RAM中若输入的数据位宽大于读出数据的位宽,那么需要对写入的数据先进行大小端转换;

  2. RAM中实现位宽转换比较烦,最好是不用于位宽转换的场景;

  3. 如果RAM需要进行位宽转换,最好是再接一级FIFO用于位宽转换,而RAM仅用于数据缓存。

  • 25
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值