Altifigence Academy

46 / 52 · Concetto

Two-Read One-Write Register Files and Bypass

Implement a synchronous two-read one-write register file with per-port write bypass and explicit validity rules.

La traduzione non è ancora disponibile. Viene mostrata la lezione originale. (한국어)

두 값을 동시에 꺼내는 저장소

연산기에서 A+B를 계산하려면 두 피연산자가 같은 주기에 필요하다. 2-read/1-write 레지스터 파일은 읽기 주소 두 개와 쓰기 주소 한 개를 제공한다. 여기서는 8개의 16비트 단어를 저장하고 두 읽기도 상승 엣지에 등록한다. 주소 폭은 3비트, 저장량은 8×16=128비트다. 주소 0도 일반 저장소이며 특별한 상수 레지스터 규칙은 없다.

읽기 포트마다 enable과 valid를 따로 둔다. 한 포트가 쉬어도 다른 포트는 읽을 수 있고, 두 포트가 같은 주소를 읽어도 된다. 동시에 서로 다른 두 주소를 읽을 수 있다는 기능은 저장량 증가와 다른 비용을 낳는다. 작은 회로는 플립플롭 배열과 두 선택망으로 구현할 수 있다. 특정 RAM을 이용한다면 읽기 포트 수를 확보하려고 저장소를 복제하고 쓰기를 함께 전달하는 구성도 고려한다. 어느 자원으로 합성되는지는 RTL 선언만으로 확정하지 않는다.

쓰는 값이 지금 읽는 값이면

이번 계약은 같은 엣지에 같은 주소를 읽고 쓸 때 새 쓰기 데이터를 응답한다. 저장 배열이 갱신되기를 기다리지 않고 wr_data를 읽기 출력의 입력으로 직접 보내는 bypass를 둔다. 포트 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}

MM^{-}는 엣지 직전 저장값이다. 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는 입력 선택을 바꾸지만 출력 등록 단계를 없애지 않는다. 주소와 요청은 엣지 전에 주고 응답은 그 엣지 뒤에 관찰한다. downstream 레지스터는 다음 상승 엣지에서 응답을 받을 수 있다. 조합형 읽기 레지스터 파일로 바꾸면 주소 변화가 출력으로 전달되는 경로와 지연 계약까지 달라지므로 단순한 코드 축약으로 취급하면 안 된다.

예제: 한 포트만 충돌하는 경우

이전에 M[2]=12, M[5]=7을 써 두었다고 하자. E0 직전에 두 읽기 enable을 켜고 rd_addr0=2, rd_addr1=5, wr_en=1, wr_addr=2, wr_data=20을 준다. E0 뒤 포트 0은 bypass된 20, 포트 1은 저장된 7을 응답한다. 이 두 유효 응답으로 덧셈을 하면 27이다. bypass 없는 read-first 구현의 19와 구분된다.

E1에는 두 읽기 주소를 모두 2로 하고 그 주소에 30을 쓴다. 두 출력 모두 30이다. E2에는 wr_en=0, wr_addr=2, wr_data=99를 둔 채 주소 2를 읽으면 두 출력은 30이어야 한다. 주소 일치만으로 우회하는 오류를 이 한 주기로 드러낼 수 있다. E3에 rd_en0=0, rd_en1=1이면 포트 0의 valid는 0, 포트 1의 valid는 1이다.

무엇을 초기화해야 하는가

active-high 동기 reset은 쓰기를 막고 두 valid를 0으로 만든다. 배열과 출력 데이터는 reset하지 않는다. 따라서 reset 뒤 출력 버스가 이전 값을 유지해도 valid=0이면 정상이다. 이미 저장된 배열 내용은 이 RTL의 reset으로 지워지지 않는다. 시스템이 reset 이후 새로운 작업만 허용한다면 그 작업의 초기화 순서를 별도로 정한다.

처음 쓰는 주소를 같은 엣지에 읽으면 이번 구현은 bypass 덕분에 새 값을 정의할 수 있다. 하지만 쓰기 없이 한 번도 초기화하지 않은 주소를 읽은 값은 여전히 미정이다. rd_valid는 요청 응답의 시점 표시이며 주소별 initialized 비트가 아니다. 검증기는 정상 읽기의 예상값을 만들기 전에 해당 주소가 알려진 값인지 확인하고, 같은 엣지 bypass인 경우를 별도로 처리해야 한다.

검증 항목은 두 읽기의 enable 조합 4가지, 주소가 같음/다름, 쓰기와 충돌하는 포트가 없음/0번/1번/둘 다, 연속 쓰기와 reset 우선순위다. 다중 쓰기 포트는 이 강의의 범위를 넘으며, 추가한다면 같은 주소에 두 쓰기가 겹칠 때의 우선순위부터 새로 정해야 한다. 포트 수가 바뀌면 기능 계약과 자원 비용이 함께 변한다.

Prova tu

M[1]=4, M[4]=9인 상태다. 두 읽기 enable이 1이고 주소가 각각 1과 4일 때 주소 4에 13을 쓰면 출력 쌍은 무엇인가? 다음 엣지에 wr_en=0, wr_addr=1, wr_data=99, 두 읽기 주소=1이라면? 마지막으로 포트 0의 enable만 0으로 만들었을 때 valid와 데이터 소비 규칙을 설명하라.

Leggi la spiegazione

첫 응답은 (4,13)이다. 포트 1만 쓰기 주소와 충돌하므로 새 값 13을 우회한다. 다음 응답은 (4,4)이며 wr_en=0이므로 99는 사용하지 않는다. 마지막 주기에는 rd_valid0=0, rd_valid1=1이다. 포트 0의 데이터 레지스터는 이전 값을 유지하지만 유효 응답으로 소비하지 않는다. 주소 0도 다른 주소와 동일하게 쓰고 읽을 수 있다.

La scelta vale per questo browser. Puoi modificarla in qualsiasi momento dal piè di pagina.