Altifigence Academy

56 / 63 · Теория

Регистровый файл с двумя чтениями, одной записью и bypass

Реализуйте два независимых порта чтения и синхронную запись, проверьте bypass для каждой коллизии и правила инициализации и valid.

Хранилище, выдающее два значения одновременно

Для A+B нужны два операнда в одном цикле. РегистровыйРегистр хранит многобитное состояние. Синхронные регистры в этом курсе записывают определённый вход на фронте тактового сигнала. Подробнее файл 2-read/1-write предоставляет два адреса чтения и один записи. Здесь хранится восемь 16-битных слов, оба чтения зарегистрированы по положительному фронту. Адрес имеет 3 бита, ёмкость 8×16=128 бит. Адрес 0 — обычное хранилище без правила константного регистра.

У каждого чтения свои enable и valid. Один порт может простаивать, пока другой читает; разрешено чтение одного адреса обоими. Возможность одновременно читать разные адреса имеет стоимость, отличную от простого увеличения ёмкости. Малый файл можно реализовать массивом триггеровТриггер записывает вход на заданном фронте такта и удерживает его до следующего фронта. Вход должен удовлетворять ограничениям setup и hold. Подробнее и двумя сетями выбора. Для определённой RAM возможна репликация памяти с общей записью ради нужного числа портов. Ресурс синтеза нельзя определить только по объявлению RTL.

Когда записываемое значение одновременно читается

Контракт возвращает новые данные при чтении и записи одного адреса на одном фронте. Bypass направляет wr_data прямо на вход выходного регистра чтения, не ожидая обновления массива. Для порта ii условие коллизии:

Hi=wr_en∧(wr_addr=rd_addri)H_i=\mathrm{wr\_en}\land(\mathrm{wr\_addr}=\mathrm{rd\_addr}_i)

При rd_eni=1\mathrm{rd\_en}_i=1 ответ:

Ri+={wr_data,Hi=1M−[rd_addri],Hi=0R_i^{+}=\begin{cases} \mathrm{wr\_data}, & H_i=1\\ M^{-}[\mathrm{rd\_addr}_i], & H_i=0 \end{cases}

M−M^{-} — хранимое значение до фронта. HiH_i отдельно сравнивает каждый адрес чтения. Если из-за коллизии одного порта направить запись на оба, исказится и операнд другого адреса. Пропуск wr_en также создаст ложный обход при случайном совпадении wr_addr без реальной записи.

SystemVerilog
module regfile8x16_2r1w (
  input  logic        clk, rst, wr_en,
  input  logic [2:0]  wr_addr,
  input  logic [15:0] wr_data,
  input  logic        rd_en0, rd_en1,
  input  logic [2:0]  rd_addr0, rd_addr1,
  output logic [15:0] rd_data0, rd_data1,
  output logic        rd_valid0, rd_valid1
);
  timeunit 1ns;
  timeprecision 1ps;
  logic [15:0] mem [0:7];

  always_ff @(posedge clk) begin
    if (rst) begin
      rd_valid0 <= 1'b0;
      rd_valid1 <= 1'b0;
    end else begin
      rd_valid0 <= rd_en0;
      rd_valid1 <= rd_en1;
      if (wr_en)
        mem[wr_addr] <= wr_data;
      if (rd_en0)
        rd_data0 <= (wr_en && wr_addr == rd_addr0)
                  ? wr_data : mem[rd_addr0];
      if (rd_en1)
        rd_data1 <= (wr_en && wr_addr == rd_addr1)
                  ? wr_data : mem[rd_addr1];
    end
  end
endmodule

Bypass меняет выбор входа, но не удаляет выходную регистровую ступень. Адрес и запрос подаются до фронта, ответ наблюдается после него. Следующий регистр получает ответ на следующем положительном фронте. Переход к комбинационному чтению меняет и путь от адреса к выходу, и контракт задержки; это не просто сокращение кода.

Пример: коллизия лишь одного порта

Пусть заранее записаны M[2]=12, M[5]=7. Перед E0 включите оба чтения: rd_addr0=2, rd_addr1=5, wr_en=1, wr_addr=2, wr_data=20. После E0 порт 0 отвечает обходным 20, порт 1 — сохранённым 7. Сумма действительных ответов 27, в отличие от 19 у read-first без bypass.

На E1 задайте оба адреса чтения 2 и запишите туда 30: оба выхода 30. На E2 при wr_en=0, wr_addr=2, wr_data=99 читайте адрес 2: оба выхода должны быть 30. Этот цикл выявляет обход только по совпадению адреса. На E3 при rd_en0=0, rd_en1=1 valid порта 0 равен 0, порта 1 — 1.

Каждый столбец — запись наблюдения одного положительного фронтаПоложительный фронт — момент перехода такта из 0 в 1. Его следует отличать от уровня, означающего весь интервал CLK=1. Подробнее. Входы показаны непосредственно перед фронтом, состояния со словом «после» в имени — сразу после обновления. Выравнивание столбцов обозначает порядок выборок, а не физическую задержку распространенияЗадержка распространения — время от изменения входа до установления правильного выхода. Логическая эквивалентность выражений и их временные характеристики — разные вопросы. Подробнее.
Предварительно M[2]=12, M[5]=7, оба enable чтения всегда 1. Адрес записи — 2. В последнем столбце wr_en=0, поэтому обход wr_data=99 запрещён.

Два порта независимо выбирают данные при одной и той же записи
Показать данные диаграммы
Данные диаграммы: каждый символ — один интервал; точка сохраняет предыдущее состояние; p — один тактовый цикл.
СигналДиаграммаЗначения шины
фронт234E0 → E1 → E2
wr_en1.0
wr_data23420 → 30 → 99
rd_addr02..2
rd_addr123.5 → 2
out0 после23.20 → 30
out1 после23.7 → 30

Что нужно инициализировать

Синхронный active-high reset блокирует запись и обнуляет оба valid. Массив и выходные данные не сбрасываются. Поэтому сохранённая на выходной шине старая величина при valid=0 после reset нормальна. Этот RTL не стирает прежнее содержимое массива. Если система после reset допускает лишь новую работу, определите её инициализацию отдельно.

Первое чтение адреса одновременно с его первой записью здесь получает определённое новое значение благодаря bypass. Но чтение никогда не инициализированного адреса без записи остаётся неопределённым. Rd_valid обозначает момент ответа, а не initialized-бит адреса. Эталон перед обычным чтением проверяет известность адреса и отдельно обрабатывает обход того же фронта.

Проверяйте четыре сочетания enable чтения, одинаковые и разные адреса, коллизию ни с одним портом, с 0, с 1, с обоими, последовательные записи и приоритет reset. Несколько портов записи вне рамок лекции; при добавлении сначала задайте приоритет двух записей в один адрес. Изменение числа портов меняет и функциональный контракт, и стоимость ресурсов.

Попробуйте сами

M[1]=4, M[4]=9. Оба чтения разрешены по адресам 1 и 4; в 4 записывают 13. Какова пара выходов? На следующем фронте wr_en=0, wr_addr=1, wr_data=99, оба адреса чтения 1. Каков результат? Наконец, выключите только enable порта 0 и объясните valid и потребление данных.

Прочитать объяснение

Первый ответ (4,13): только порт 1 совпадает с адресом записи и получает новое 13 через bypass. Следующий (4,4): при wr_en=0 значение 99 не используется. В последнем цикле rd_valid0=0, rd_valid1=1. Регистр данных порта 0 хранит прежнее значение, которое нельзя потреблять как действительный ответ. Адрес 0 тоже читается и записывается как обычный.

Выбор действует в этом браузере. Его можно изменить внизу страницы.