홈으로 돌아가기

FPGA용 멀티스레드 RISC-V 소프트 프로세서

이 기사는 shadow registers와 하드웨어 hart 스위칭을 사용한 FPGA용 멀티스레드 RISC-V 소프트 프로세서 구현을 설명합니다. 주요 모듈의 전체 Verilog 코드 제공: reg_file, PC, CSR, hart_table. 이 접근법은 인터럽트 처리를 간소화하고 FPGA 리소스를 최적화합니다.

FPGA 내 하드웨어 멀티스레딩 RISC-V: 전체 구현
Advertisement 728x90

FPGA용 RISC-V 소프트 코어 프로세서에서 하드웨어 멀티스레딩 구현하기

RISC-V 기반 소프트 코어 프로세서의 멀티스레드 마이크로아키텍처는 하트 상태를 저장하기 위해 섀도우 레지스터를 사용하여 소프트웨어 개입 없이 빠른 컨텍스트 전환을 가능하게 합니다. 이는 FPGA 프로젝트에서 비동기 이벤트 처리를 단순화하고, 인터럽트 컨트롤러 부하를 최소화하며, 코드 양을 줄입니다. 이 구현은 단일 권한 수준과 공유 주소 공간을 가진 시스템을 대상으로 합니다.

마이크로아키텍처 기본 원리

핵심 요소는 각 하트(RISC-V 용어 사용)에 대한 섀도우 레지스터 배열입니다. 각 하트는 레지스터 x0-x31과 PC의 복사본에 자신의 상태를 저장합니다. ALU, 메모리, 주변 장치 및 CSR 레지스터는 공유됩니다. 데이터 보호는 소프트웨어 수준에서 구현됩니다.

기본 명령어 세트 I+Zicsr가 지원됩니다. 스레드 관리는 CSR 레지스터와 하트 테이블(hart_table)을 통해 처리됩니다. 하트 전환은 시스템 타이머를 기반으로 순환적으로 발생하며, 그 하위 비트가 테이블을 주소 지정합니다.

Google AdInline article slot

하트 활동 비트는 PC, 레지스터 및 메모리에 대한 쓰기를 제어하고 비활성 스레드에 대한 ALU 파이프라인을 재설정합니다.

CSR 레지스터 모듈

CSR 블록은 멀티스레딩 호환성을 위해 독립적인 읽기 및 쓰기 포트로 나뉩니다:

module rv_csr
#(
  parameter DATA_WIDTH=32, 
  parameter ADDR_WIDTH=12,
  parameter CSR_size = 32
  )
(input clk,
  input [(ADDR_WIDTH-1):0] csr_addr_in,
  input [(DATA_WIDTH-1):0] csr_in,
  input [(ADDR_WIDTH-1):0] csr_addr_out,
  output reg [(DATA_WIDTH-1):0] csr_out,
  input csr_wr,
  input en
);
// csr register file
reg [ADDR_WIDTH-1:0] csr_reg[0:CSR_size-1];

always @ (posedge clk)
begin
  case (csr_addr_in)
    32'h0 : begin
      if (csr_wr&en) begin
        csr_reg[0] <= csr_in;
      end 
    end
    default: begin
      csr_reg[1] <= 32'h555;
    end
  endcase
  case (csr_addr_out)
    32'h0 : begin
      csr_out <= csr_reg[0];
    end
    default: begin
      csr_out<=32'hAAA;
    end
  endcase
end

endmodule

하트 지원 레지스터 파일

멀티스레드 레지스터 파일은 8개의 하트를 위한 RAM 배열을 구현합니다. 읽기/쓰기 작업은 hart_in/hart_out 번호로 주소 지정됩니다:

Google AdInline article slot
module rv_reg_file
#(
  parameter DATA_WIDTH=32, 
  parameter ADDR_WIDTH=5
  )
( input clk,
  input [(ADDR_WIDTH-1):0] rs1,
  input [(ADDR_WIDTH-1):0] rs2,
  input [(ADDR_WIDTH-1):0] rd,
  output reg [(DATA_WIDTH-1):0] Rs1_out,
  output reg [(DATA_WIDTH-1):0] Rs2_out,
  input [(DATA_WIDTH-1):0] Rd_input,
  input [2:0] hart_in, // hart to read out data from
  input [2:0] hart_out, // hart to write data to
  input we,
  input en,
  output reg [(DATA_WIDTH-1):0] x1_out,
  output reg [(DATA_WIDTH-1):0] x2_out,
  output reg [(DATA_WIDTH-1):0] x3_out,
  output reg [(DATA_WIDTH-1):0] x4_out,
  output reg [(DATA_WIDTH-1):0] x5_out
);

// RAM array
  reg [DATA_WIDTH-1:0] ram[0:2**ADDR_WIDTH-1][0:7];
  wire rd_nonzero;
  wire rs1_nonzero;
  wire rs2_nonzero;
  assign rd_nonzero = |rd;
  assign rs1_nonzero = |rs1;
  assign rs2_nonzero = |rs2;

always @ (posedge clk)
  begin
    if (en & we & rd_nonzero) ram[rd][hart_in] <= Rd_input;
  end

always @ (*)
  begin
    Rs1_out <= rs1_nonzero ? ram[rs1][hart_out] : 32'h0;
    Rs2_out <= rs2_nonzero ? ram[rs2][hart_out] : 32'h0;
    x1_out <= ram[1][hart_out];
    x2_out <= ram[2][hart_out];
    x3_out <= ram[3][hart_out];
    x4_out <= ram[4][hart_out];
    x5_out <= ram[5][hart_out];
  end
// */
endmodule

스레드용 프로그램 카운터

PC는 pc.txt 파일에서 초기화된 레지스터 배열로 구현됩니다. 증가 및 로드 작업은 활성 하트에 대해서만 발생합니다:

module rv_pc
#(
parameter WIDTH=32
)
(
  input clk,
  input rst_n,
  input en,
  input pc_load,
  input [WIDTH-1:0] pc_next,
  output [WIDTH-1:0] pc,
  output reg [WIDTH-1:0] pc_plus,
  input [2:0] hart_in,
  input [2:0] hart_out
);
reg [WIDTH-1:0] pc_reg[0:7];
// read initial PCs data values
initial
$readmemh("pc.txt",pc_reg);

always@(posedge clk or negedge rst_n)
  begin
    if (en) begin
      if(pc_load==1'b1)
        pc_reg[hart_in] <= pc_next;
      else
        pc_reg[hart_in] <= pc_reg[hart_in] + 3'h4;
      end
    end
assign pc = pc_reg[hart_out];

always @ *
  begin
    pc_plus <= pc_reg[hart_out] + 3'h4;
  end

endmodule

하트 테이블 및 관리

hart_table은 타이머로 주소 지정되는 8개의 항목(4비트: 1 활동 비트 + 3 하트 번호 비트)을 가진 ROM입니다. 64비트 시스템 타이머는 순환 카운터이자 시스템 크로노미터 역할을 합니다.

전체 모듈 목록:

Google AdInline article slot
  • rv_pc — 멀티스레드 프로그램 카운터
  • rv_mem — 통합 메모리
  • rv_desh — 파이프라인 재설정 디코더
  • rv_reg_file — 섀도우 레지스터
  • rv_alu_v — 파이프라인 ALU
  • rv_csr — 공유 특수 레지스터
  • rv_hart_reg — 하트 상태
  • rv_timer — 64비트 타이머
  • rv_hart_table — 스레드 구성

구현 장점

  • 빠른 전환: 레지스터 저장/복원 없이 하드웨어 기반
  • IRQ 단순화: 인터럽트 벡터 대신 스레드 사용
  • RISC-V 호환성: 하트 개념 지원
  • FPGA 최적화: 공유 자원, 최소 논리

핵심 포인트

  • 섀도우 레지스터는 각 하트의 전체 아키텍처 상태를 저장합니다.
  • 공유 CSR은 정확한 작동을 위해 별도의 R/W 포트가 필요합니다.
  • 하트 활동은 모든 쓰기를 제어하고 파이프라인을 재설정합니다.
  • 타이머는 hart_table을 순환적으로 주소 지정하여 라운드 로빈 스케줄링을 보장합니다.
  • 메모리 보호 및 동기화는 OS/RTOS의 책임입니다.

— Editorial Team

Advertisement 728x90

다음 읽기