返回首页

多线程 RISC-V FPGA 软处理器

本文描述了用于 FPGA 的多线程 RISC-V 软处理器的实现,使用 shadow registers 和硬件 hart 切换。提供了关键模块的完整 Verilog 代码:reg_file、PC、CSR、hart_table。该方法简化了中断处理并优化了 FPGA 资源。

FPGA 中的硬件多线程 RISC-V:完整实现
Advertisement 728x90

在FPGA中为RISC-V软核处理器实现硬件多线程

基于RISC-V的软核处理器多线程微架构使用影子寄存器存储硬件线程(hart)状态,无需软件干预即可实现快速上下文切换。这简化了FPGA项目中异步事件的处理,最小化中断控制器负载并减少代码量。该实现针对具有单一特权级别和共享地址空间的系统。

微架构基础

关键要素是为每个hart(使用RISC-V术语)设置影子寄存器数组。每个hart将其状态保存在寄存器x0-x31和程序计数器(PC)的副本中。算术逻辑单元(ALU)、内存、外设和控制状态寄存器(CSR)保持共享。数据保护在软件层面实现。

支持基础指令集I+Zicsr。线程管理通过CSR寄存器和hart表(hart_table)处理。Hart切换基于系统定时器循环进行,其低位用于寻址表。

Google AdInline article slot

Hart活动位控制对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寄存器文件
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

支持Hart的寄存器文件

多线程寄存器文件实现了一个支持8个hart的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
  input [2:0] hart_out, // 写入数据的hart
  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数组
  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文件初始化的寄存器数组。递增和加载操作仅针对活动hart进行:

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];
// 读取初始PC数据值
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表与管理

hart_table是一个包含8个条目的ROM(4位:1个活动位 + 3个hart编号位),由定时器寻址。64位系统定时器既用作循环计数器,也用作系统计时器。

完整模块列表:

Google AdInline article slot
  • rv_pc — 多线程程序计数器
  • rv_mem — 统一内存
  • rv_desh — 带流水线重置的解码器
  • rv_reg_file — 影子寄存器
  • rv_alu_v — 流水线ALU
  • rv_csr — 共享特殊寄存器
  • rv_hart_reg — hart状态
  • rv_timer — 64位定时器
  • rv_hart_table — 线程配置

实现优势

  • 快速切换:基于硬件,无需保存/恢复寄存器
  • 中断简化:使用线程而非中断向量
  • RISC-V兼容性:支持hart概念
  • FPGA优化:共享资源,最小化逻辑

关键要点

  • 影子寄存器存储每个hart的完整架构状态
  • 共享CSR需要独立的读写端口以确保正确操作
  • Hart活动控制所有写入并重置流水线
  • 定时器循环寻址hart_table,确保轮询调度
  • 内存保护和同步由操作系统/实时操作系统负责

— Editorial Team

Advertisement 728x90

继续阅读