Память с произвольным доступом (RAM)

Для моделирования RAM в Verilog поддерживается использование двумерных таблиц. Поведенческие модели памяти создаются путём объявления таблицы регистров. Любое слово в этой таблице может быть доступно с использованием его индекса в таблице. Однако для доступа к отдельному биту в пределах слова памяти необходимо использовать вспомогательный временный регистр.

Объявление памяти:

reg [7:0] memory_name [0:255];

Здесь [7:0] - это ширина слова, а [0:255] - это объём памяти.

Запись значений в память:

memory_name[address] = data_in;

Чтение значений:

data_out = memory_name[address];

Прямой доступ к биту

Часто необходимо прочитать отдельный бит из целого слова памяти. К сожалению, Verilog не позволяет прямо читать или писать отдельные биты. Решением этой проблемы является использование вспомогательного регистра:

data_out = memory_name[address];
data_out_singur_bit = data_out[3]; //читаем только 4-й бит из целого слова.

Описание базового модуля RAM на языке Verilog

module ram (clk, address, data, cs, we, oe);
parameter DATA_WIDTH = 8 ;
parameter ADDR_WIDTH = 8 ;
parameter RAM_DEPTH = 1 << ADDR_WIDTH;

input clk ;
input [ADDR_WIDTH-1:0] address ;
input cs ;
input we ;
input oe ;
inout [DATA_WIDTH-1:0] data ;

reg [DATA_WIDTH-1:0] data_out ;
reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
reg oe_r;

assign data = (cs && oe && !we) ? data_out : 8'bz;

always @ (posedge clk)
begin
  if ( cs && we ) begin
    mem[address] = data;
  end
end

always @ (posedge clk)
begin
  if (cs && !we && oe) begin
    data_out = mem[address];
    oe_r = 1;
  end else begin
    oe_r = 0;
  end
end
endmodule

Тестовая скамья для модуля RAM:

module tb;
reg clk, cs, we, re;
reg [7:0] address;
reg [7:0] data;
wire [7:0] data_out;

assign data_out = (we==1)?data:'z;

ram r0(clk, address, data_out, cs, we, re);

initial begin
  cs = 1;
  clk = 0;
  address = 0;
  $monitor("data = %b, address=b, read=%b, write=%b", data_out, address, re, we);
end

always begin
  #5
  clk = !clk;
end

always begin
  address = address + 1;
  data = $random;
  we = 1;
  #20;
  we = 0;
  re = 1;
  #20;
  re = 0;
end
endmodule

Расширение по ширине слова

Для создания модуля памяти (на основе существующего модуля) с большей шириной слова необходимо объединить несколько модулей следующим образом:

  1. Поскольку адресное пространство остаётся неизменным, шина адреса подключается параллельно ко всем модулям.

  2. Вспомогательные сигналы, такие как (chip select, read enable, write enable), подключаются параллельно.

  3. Шина данных расширяется в количество раз, равное количеству подмодулей, участвующих в расширении.


Расширение по адресному пространству

Для создания модуля памяти (на основе существующего модуля) с большим адресным пространством необходимо объединить несколько модулей следующим образом:

  1. Поскольку ширина слова остаётся неизменной, шина данных подключается параллельно ко всем модулям.

  2. Вспомогательные сигналы, такие как (clock, read enable, write enable), подключаются параллельно.

  3. Шина адреса используется специальным образом. Для расширения адресного пространства добавляются более значащие биты к шине адреса. Эти биты используются для выбора одного модуля, который должен быть активным в данный момент. Этот выбор осуществляется с использованием демультиплексора, который перенаправляет CS из верхней иерархии к подмодулям, на основе которых создаётся новый расширенный модуль.


Ход работы:

  1. Реализуйте модуль RAM на языке Verilog;
  2. Реализуйте тестовую скамью для модуля RAM;
  3. Синтезируйте модуль RAM;
  4. Реализуйте расширение модулей RAM по ширине слова;
  5. Реализуйте тестовую скамью для модуля, расширенного по ширине слова;
  6. Реализуйте расширение модулей RAM по адресному пространству;
  7. Реализуйте тестовую скамью для модуля, расширенного по адресному пространству.