verilog 实现 ram的一些代码以及理解

单口RAM

// Quartus II Verilog Template
// Single port RAM with single read/write address

module single_port_ram
(
    input [(DATA_WIDTH-1):0] data,
    input [(ADDR_WIDTH-1):0] addr,
    input we, clk,
    output reg [(DATA_WIDTH-1):0] q
);

    parameter DATA_WIDTH = 8;
    parameter ADDR_WIDTH = 6;

    // Declare the RAM variable
    reg [DATA_WIDTH-1:0] ram[2**ADDR_WIDTH-1:0];   //红色字代表存储器的深度,为2的ADDR_WIDTH次幂-1 : 0

    always @ (posedge clk)
    begin
        // Write
        if (we)
           ram[addr] = data;

        // Read returns NEWdata at addr if we == 1'b1. This is the                
        // natural behavior ofTriMatrix memory blocks in Single Port
        // mode
       //如果we == 1'b1,则读取会在addr返回新数据。这是TriMatrix内存块在单端口模式下的自然行为
q <= ram[addr];
    end

endmodule

简单双口RAM单时钟

// Quartus II Verilog Template
// Simple Dual Port RAM with separate read/write addresses and
// single read/write clock

module simple_dual_port_ram_single_clock
(
    input [(DATA_WIDTH-1):0] data,
    input [(ADDR_WIDTH-1):0] read_addr, write_addr,
    input we, clk,
    output reg [(DATA_WIDTH-1):0] q
);

    parameter DATA_WIDTH = 8;
    parameter ADDR_WIDTH = 6;

    // Declare the RAM variable
    reg [DATA_WIDTH-1:0] ram[2**ADDR_WIDTH-1:0];

    always @ (posedge clk)
    begin
        // Write
        if (we)
           ram[write_addr] <= data;

       // Read (if read_addr == write_addr, return OLD data). To return
        // NEW data, use =(blocking write) rather than <= (non-blocking write)
        // in the writeassignment. NOTE: NEW data may require extra bypass
        // logic around theRAM.
        //读取(如果read_addr== write_addr,则返回OLD数据)。要返回NEW数据,请在写入分配中使用=而不是<=。注意:新数据可能需要RAM周围的额外旁路逻辑。
q <= ram[read_addr];
    end

endmodule

另一种思路《基于nios 2 的嵌入式sopc系统设计与verilog 开发实例》p107-108
关键部分摘要
读新数据:

       //writeoperation
       always@(posedgeclk)
       begin
              if(we)
                     ram[w_addr]<= d;
              addr_reg <= r_addr;   //其缓存的是地址,则读的数据只是会延迟一个时钟周期
       end
//read operation
       assignq = ram[addr_reg];
   读旧数据:
       //writeoperation
       always@(posedgeclk)
       begin
              if(we)
                     ram[w_addr]<= d;
              data_reg <= ram[r_addr];   //(读写同时操作同一地址对应的空间时)其缓存的是旧数据,因为当读写是同一时钟上升沿触发,
       end
//read operation
       assignq = data_reg;

真双口RAM

cyclone 系列的存储器的功能如下:

  1. 当读操作和写操作在同一个端口发生时,要写入存储器的数据新数据被读取出来。
  2. 当读操作和写操作发生在不同的端口,但使用相同的地址时,存储器中的旧数据被读取出来,需要附加的旁路逻辑恢复新数据。
  3. 通过两个端口向同一个地址写数据将导致无法预料的行为。

ROM

真正的ROM时一个组合逻辑电路,但是可以用一个单口RAM通过禁止写入来模拟出一个ROM。但是模拟的ROM有缓存器和时钟信号。

编辑 重设标签(回车键确认) 标为违禁 关闭 合并 删除

提问于 2019-04-27 08:13:30 +0800

这个帖子被标记为一个社区wiki

这个帖子是一个wiki(维基). 任何一个积分 >500的人都可以完善它