Skip to main content

2 PE Array

下面按文件中出现的顺序,逐模块、逐行解析。


模块一:compute_tb_start​

1.1 模块声明​

module compute_tb_start ##(parameter PE_WIDTH=8,LOG_MAX_TILE_SIZE=10,REF_LEN_WIDTH=10)
(
input clk,
input [LOG_MAX_TILE_SIZE:0] marker,
input [REF_LEN_WIDTH+1:0] conv_value,
output logic [REF_LEN_WIDTH-1:0] conv_query_idx,
output logic [REF_LEN_WIDTH-1:0] conv_ref_idx,
output logic [1:0] conv_state
);

作用:把收敛指针 conv_value 解码成 traceback 起点坐标和状态。

端口含义
marker当前 tile 的 marker 值
conv_value收敛指针,格式 {ref_idx, state[1:0]}
conv_query_idx解码后的 query 坐标
conv_ref_idx解码后的 ref 坐标
conv_state解码后的状态(0=H, 1=D, 2=I)

1.2 内部分解​

wire [REF_LEN_WIDTH-1:0] conv_ref_idx_next;
wire [1:0] conv_marker;
assign {conv_ref_idx_next,conv_marker}=conv_value;
  • conv_value 是 REF_LEN_WIDTH + 2 位;
  • 高 REF_LEN_WIDTH 位是 ref 坐标;
  • 低 2 位是状态标记。

1.3 时序逻辑​

always @(posedge clk ) begin
conv_ref_idx<=conv_ref_idx_next;
conv_query_idx<=marker-conv_ref_idx_next-(conv_marker==3);
case (conv_marker)
0: conv_state<=0;
2: conv_state<=1;
1: conv_state<=2;
3: conv_state<=0;
endcase
end
endmodule

逐行解释:

  • conv_ref_idx <= conv_ref_idx_next:ref 坐标直接寄存。
  • conv_query_idx <= marker - conv_ref_idx_next - (conv_marker==3):
    • 在反对角线上,ref_idx+query_idx=markerref\_idx + query\_idx = marker;
    • 所以 query_idx=marker−ref_idxquery\_idx = marker - ref\_idx;
    • conv_marker==3 时(marker 前一格),再多减 1。
  • case (conv_marker):
    • 0(H)→ conv_state = 0
    • 2(D)→ conv_state = 1
    • 1(I)→ conv_state = 2
    • 3(marker 前一格)→ conv_state = 0

注意:conv_marker 的编码与 conv_state 的编码不同,这里做了映射。


模块二:PE_Array(主体)​

2.1 模块声明与参数​

module PE_Array ##(
parameter PE_WIDTH = 7,
parameter DATA_WIDTH = 8,
parameter NUM_BLOCK = 4,
parameter NUM_PE = 32,
parameter LOG_NUM_PE = $clog2(NUM_PE),
parameter MAX_TILE_SIZE = 64,
parameter LOG_MAX_TILE_SIZE = $clog2(MAX_TILE_SIZE),
parameter REF_LEN_WIDTH = 8,
parameter QUERY_LEN_WIDTH = 8,
parameter PARAM_ADDR_WIDTH = 8,
parameter CONV_SCORE_WIDTH = 1 + 2*(REF_LEN_WIDTH + 2) + 3*PE_WIDTH+1,
parameter TB_DATA_WIDTH = 4*NUM_PE,
parameter TB_ADDR_WIDTH = $clog2(2*(MAX_TILE_SIZE/NUM_PE)*MAX_TILE_SIZE)
)(
参数含义
PE_WIDTH分数位宽
NUM_BLOCKtile 内 block 数量
NUM_PEPE 阵列宽度
MAX_TILE_SIZEtile 最大尺寸
CONV_SCORE_WIDTHscore_bram 数据宽度(conv_check + CH + CI + H + I + ad_max)
TB_DATA_WIDTHtraceback BRAM 数据宽度 = 4*NUM_PE
TB_ADDR_WIDTHtraceback BRAM 地址宽度

2.2 输入端口​

input logic clk,
input logic rst,
input logic start,
信号含义
clk时钟
rst复位
start启动信号,来自 Host
input logic [13*PE_WIDTH - 1: 0] in_param,
input logic [REF_LEN_WIDTH - 1:0] total_ref_length,
input logic [QUERY_LEN_WIDTH - 1:0] total_query_length,
信号含义
in_param13 个打分参数(替换矩阵 + gap + xdrop)
total_ref_length参考序列总长
total_query_length查询序列总长
input logic complement_ref_in,
output logic [(LOG_MAX_TILE_SIZE/NUM_BLOCK): 0] ref_bram_addr,
input logic [DATA_WIDTH - 1:0] ref_bram_data_out,

input logic complement_query_in,
output logic [(LOG_MAX_TILE_SIZE/NUM_BLOCK): 0] query_bram_addr,
input logic [DATA_WIDTH - 1:0] query_bram_data_out,
信号含义
complement_ref_in / complement_query_in是否取互补
ref_bram_addr / query_bram_addrBRAM 读地址
ref_bram_data_out / query_bram_data_outBRAM 读出的 ASCII 字符
output logic rstb,
output logic regceb,
output logic score_bram_wr_en_ext,
output logic score_bram_rd_en,
output logic [CONV_SCORE_WIDTH - 1:0] score_bram_data_in,
input logic [CONV_SCORE_WIDTH - 1:0] score_bram_data_out,
output logic [LOG_MAX_TILE_SIZE - 1: 0] score_bram_addr_wr,
output logic [LOG_MAX_TILE_SIZE - 1: 0] score_bram_addr_rd,
信号含义
rstb, regcebscore_bram 的复位和输出寄存器使能
score_bram_wr_en_extscore_bram 写使能
score_bram_rd_enscore_bram 读使能
score_bram_data_in/outscore_bram 数据
score_bram_addr_wr/rdscore_bram 读写地址
output logic tb_bram_wr_en,
output logic [TB_DATA_WIDTH - 1: 0] tb_bram_data_in,
input logic [TB_DATA_WIDTH - 1: 0] tb_bram_data_out,
output logic [TB_ADDR_WIDTH-1: 0] tb_bram_addr_reg,
信号含义
tb_bram_wr_entraceback BRAM 写使能
tb_bram_data_intraceback BRAM 写入数据(4-bit dir × NUM_PE)
tb_bram_data_outtraceback BRAM 读出数据
tb_bram_addr_regtraceback BRAM 地址
output logic last_tile,
input logic [PE_WIDTH - 1: 0] INF,
input logic [LOG_MAX_TILE_SIZE : 0] marker,
input logic signed [PE_WIDTH - 1: 0] xdrop_value,
input [1:0] init_state,
信号含义
last_tile是否是最后一个 tile
INF负无穷
marker当前 tile 的 marker
xdrop_valueX-Drop 阈值
init_state初始状态(0=H, 1=D, 2=I, 3=对角)
output logic [1: 0] tb_pointer,
output logic tb_valid,
output logic [QUERY_LEN_WIDTH-1:0] query_next_tile_addr,
output logic [REF_LEN_WIDTH-1:0] ref_next_tile_addr,
output logic [1:0] next_tile_init_state,
output commit,
output traceback,
output logic stop
);
信号含义
tb_pointer回溯指针输出(2-bit)
tb_valid回溯指针有效
query_next_tile_addr下一个 tile 的 query 起点
ref_next_tile_addr下一个 tile 的 ref 起点
next_tile_init_state下一个 tile 的初始状态
commit提交信号
traceback回溯状态指示
stop停止信号

2.3 局部参数与状态枚举​

localparam PARAM_WIDTH = 4 * PE_WIDTH;

logic score_bram_wr_en,score_bram_wr_en_delayed;
enum {WAIT,READ_PARAM,SET_PARAM,STREAM_REF_START,STREAM_REF,STREAM_REF_CONTINUE,STREAM_REF_DONE,STREAM_REF_STOP,DONE,TB,EXIT,DONE2} STATE;

状态枚举:

状态含义
WAIT等待 start
READ_PARAM读取参数
SET_PARAM设置参数并开始流式输入 query
STREAM_REF_START开始流式输入 ref
STREAM_REF正常流式计算
STREAM_REF_CONTINUEblock 结束,准备下一个 block
STREAM_REF_DONEref 流式完成(未使用)
STREAM_REF_STOP停止(未使用)
DONE分数计算完成
TB开始 traceback
EXIT退出
DONE2中间状态,等待进入 TB

2.4 序列与参数信号​

logic [2:0] ref_nt;
logic [2:0] query_nt;

logic block; // 0 for first block otherwise 1

logic [PARAM_WIDTH - 1:0] param;
logic [PARAM_WIDTH - 1:0] out_param;
信号含义
ref_ntref 碱基(3-bit nt)
query_ntquery 碱基(3-bit nt)
block是否是后续 block
param / out_paramnt2param 的输入输出
logic [REF_LEN_WIDTH-1:0] curr_ref_length;
logic [QUERY_LEN_WIDTH-1:0] curr_query_length;
  • curr_ref_length:当前 ref 已流式输入的长度;
  • curr_query_length:当前 query 已流式输入的长度。
logic init_n;
logic init_in [0: NUM_PE - 1];
logic [NUM_PE - 1: 0] set_param;
信号含义
init_n初始化脉冲(用于收敛检测)
init_in[i]PE[i] 的初始化信号
set_param[i]PE[i] 的参数加载使能(移位寄存器)
logic [2: 0] ref_in [0: NUM_PE - 1];
logic signed [PE_WIDTH - 1: 0] sub_A_in;
logic signed [PE_WIDTH - 1: 0] sub_C_in;
logic signed [PE_WIDTH - 1: 0] sub_G_in;
logic signed [PE_WIDTH - 1: 0] sub_T_in;
logic signed [PE_WIDTH - 1: 0] sub_N_in;
logic signed [PE_WIDTH - 1: 0] gap_open_in;
logic signed [PE_WIDTH - 1: 0] gap_extend_in;
信号含义
ref_in[i]PE[i] 的 ref 碱基输入
sub_A/C/G/T/N_in替换矩阵参数
gap_open_in, gap_extend_ingap 罚分
logic [REF_LEN_WIDTH - 1: 0] curr_ref_idx;
logic [REF_LEN_WIDTH - 1: 0] ref_idx_in [0: NUM_PE - 1];
logic [QUERY_LEN_WIDTH - 1: 0] query_idx_in [0: NUM_PE - 1];
信号含义
curr_ref_idx当前 ref 索引(最后一个 PE 的)
ref_idx_in[i]PE[i] 的 ref 坐标
query_idx_in[i]PE[i] 的 query 坐标

2.5 分数与收敛相关信号​

logic signed [PE_WIDTH - 1: 0] conv_score;
logic [REF_LEN_WIDTH-1:0] conv_query_idx,conv_ref_idx;
logic [1:0] conv_tb_state;
wire [LOG_MAX_TILE_SIZE-1:0] block_rd_idx;
信号含义
conv_score收敛分数(未使用)
conv_query_idx, conv_ref_idx收敛点坐标
conv_tb_state收敛点状态
block_rd_idxtraceback 地址偏移读索引
logic signed [PE_WIDTH - 1: 0] global_max_score;
logic signed [PE_WIDTH - 1: 0] ad_max_score,ad_max_score_next,ad_max_score_prev_block,ad_max_score_prev_block_raw,cur_ad_max_score;
logic [REF_LEN_WIDTH - 1: 0] global_max_ref_idx;
logic [REF_LEN_WIDTH : 0] global_max_ad_idx, convergence_detected_ad_idx;
logic [QUERY_LEN_WIDTH - 1: 0] global_max_query_idx;
信号含义
global_max_score全局最大分数
ad_max_score当前 anti-diagonal 最大分数
ad_max_score_next下一个 anti-diagonal 最大分数
ad_max_score_prev_block上一个 block 的最大分数
cur_ad_max_score当前最大分数
global_max_ref_idx全局最大分数对应的 ref 坐标
global_max_ad_idx全局最大分数对应的 anti-diagonal 索引
convergence_detected_ad_idx收敛检测时的 anti-diagonal 索引
global_max_query_idx全局最大分数对应的 query 坐标
logic signed [PE_WIDTH - 1: 0] H_init;
logic signed [PE_WIDTH - 1: 0] D_init_in;

logic signed [PE_WIDTH - 1: 0] H_prev_block,H_prev_block_raw;
logic signed [PE_WIDTH - 1: 0] I_prev_block,I_prev_block_raw;
信号含义
H_initH 状态初始值(寄存器)
D_init_inD 状态初始值(固定为 -INF)
H_prev_block上一个 block 的 H 分数
I_prev_block上一个 block 的 I 分数

2.6 PE 间连接信号​

logic signed [PE_WIDTH - 1: 0] H_PE_prev [0: NUM_PE - 1];
logic signed [PE_WIDTH - 1: 0] I_PE_prev [0: NUM_PE - 1];
logic [REF_LEN_WIDTH + 1: 0] CH_PE_prev [0: NUM_PE - 1];
logic [REF_LEN_WIDTH + 1: 0] CI_PE_prev [0: NUM_PE - 1];
logic signed [PE_WIDTH - 1: 0] rd_array [0: NUM_PE - 1];
信号含义
H_PE_prev[i]PE[i] 的左邻 H 分数
I_PE_prev[i]PE[i] 的左邻 I 分数
CH_PE_prev[i]PE[i] 的左邻 H 收敛指针
CI_PE_prev[i]PE[i] 的左邻 I 收敛指针
rd_arrayreduction tree 输入数组(未使用)
logic init_out [0: NUM_PE - 1];
logic [2: 0] ref_out [0: NUM_PE - 1];
logic [TB_DATA_WIDTH - 1: 0] dir_out;

logic [REF_LEN_WIDTH - 1: 0] ref_idx_out [0: NUM_PE - 1];
logic [QUERY_LEN_WIDTH - 1: 0] query_idx_out [0: NUM_PE - 1];
信号含义
init_out[i]PE[i] 的初始化输出
ref_out[i]PE[i] 传给下一个 PE 的 ref 碱基
dir_out所有 PE 的 traceback 指针(4 bit × NUM_PE)
ref_idx_out[i]PE[i] 传给下一个 PE 的 ref 坐标
query_idx_out[i]PE[i] 传给下一个 PE 的 query 坐标
logic [REF_LEN_WIDTH + 1: 0] H_rd_value;
logic [REF_LEN_WIDTH + 1: 0] I_rd_value;
logic [REF_LEN_WIDTH + 1: 0] D_rd_value;

logic signed [PE_WIDTH - 1: 0] rd_value;
信号含义
H_rd_valuereduction tree 归约后的 H 收敛指针
I_rd_valuereduction tree 归约后的 I 收敛指针
D_rd_valuereduction tree 归约后的 D 收敛指针
rd_valuereduction tree 归约后的最大分数
logic signed [PE_WIDTH - 1: 0] H_PE [0: NUM_PE - 1];
logic signed [PE_WIDTH - 1: 0] I_PE [0: NUM_PE - 1];
logic signed [PE_WIDTH - 1: 0] D_PE [0: NUM_PE - 1];
logic [REF_LEN_WIDTH + 1: 0] CH_PE [0: NUM_PE - 1];
logic [REF_LEN_WIDTH + 1: 0] CI_PE [0: NUM_PE - 1];
logic [REF_LEN_WIDTH + 1: 0] CD_PE [0: NUM_PE - 1];
信号含义
H_PE[i]PE[i] 的 H 分数输出
I_PE[i]PE[i] 的 I 分数输出
D_PE[i]PE[i] 的 D 分数输出
CH_PE[i]PE[i] 的 H 收敛指针
CI_PE[i]PE[i] 的 I 收敛指针
CD_PE[i]PE[i] 的 D 收敛指针

2.7 边界与控制信号​

logic lower_bound_check;
logic [$clog2(MAX_TILE_SIZE/NUM_PE): 0] block_count;
logic [REF_LEN_WIDTH - 1: 0] start_idx;
logic [REF_LEN_WIDTH - 1: 0] lower_bound_value;
信号含义
lower_bound_check是否已确定 lower bound
block_countblock 计数器
start_idx当前 block 的 ref 起点
lower_bound_value下一个 block 的 ref 起点
logic [TB_ADDR_WIDTH-1: 0] tb_bram_start_sub_ref_start [MAX_TILE_SIZE/NUM_PE - 1: 0];
  • 存每个 block 的 traceback BRAM 地址偏移。

2.8 收敛与控制信号​

logic conv;
logic C1,C2,C3,C4,C5;
logic query_oflow;
logic ref_oflow;
信号含义
conv收敛标志(寄存器)
C1ref 边界条件
C2query 边界条件
C3X-Drop 剪枝条件
C4收敛检测完成条件
C5收敛确认条件
query_oflowquery 越界
ref_oflowref 越界
always @(posedge clk ) begin
if(rst)
ref_oflow<=0;
else
ref_oflow<=curr_ref_length>=total_ref_length;
end
  • ref_oflow 在当前 ref 长度达到总长时置 1。
always @(posedge clk ) begin
if(rst)
query_oflow<=0;
else
query_oflow<=curr_query_length>=total_query_length;
end
  • query_oflow 同理。

2.9 Traceback 控制信号​

logic [REF_LEN_WIDTH+1:0] global_max_conv_idx;
// Traceback
logic tb_start;
logic [1:0] tb_state;
logic [TB_ADDR_WIDTH-1: 0] tb_bram_addr_out;
logic [TB_ADDR_WIDTH-1: 0] tb_bram_addr;
logic tb_done;
wire last_PE_not_droped;
wire [REF_LEN_WIDTH:0] curr_ad_idx;
assign curr_ad_idx= (curr_ref_length) + (curr_query_length - NUM_PE);
信号含义
global_max_conv_idx全局最大分数对应的收敛指针
tb_starttraceback 启动
tb_statetraceback 状态(未使用)
tb_bram_addr_outtraceback BRAM 读地址
tb_bram_addrtraceback BRAM 写地址
tb_donetraceback 完成
last_PE_not_droped最右 PE 未被剪枝
curr_ad_idx当前 anti-diagonal 索引
logic past_marking;
always @(posedge clk ) begin
past_marking<=curr_ad_idx>marker+1;
end
  • past_marking 表示当前 anti-diagonal 已超过 marker + 1。

2.10 写回与流水线信号​

wire [CONV_SCORE_WIDTH - 1:0] prev_block_to_write;
wire H_converged_this_block,H_converged,I_converged,D_converged, this_ad_converged;
assign prev_block_to_write={this_ad_converged,H_converged,CH_PE[NUM_PE - 1], CI_PE[NUM_PE - 1], H_PE[NUM_PE - 1], I_PE[NUM_PE - 1],ad_max_score_next};
  • prev_block_to_write 打包了要写入 score_bram 的所有信息:
    • this_ad_converged:本 anti-diagonal 是否收敛;
    • H_converged:H 是否收敛;
    • CH_PE[NUM_PE-1]:最右 PE 的 H 收敛指针;
    • CI_PE[NUM_PE-1]:最右 PE 的 I 收敛指针;
    • H_PE[NUM_PE-1]:最右 PE 的 H 分数;
    • I_PE[NUM_PE-1]:最右 PE 的 I 分数;
    • ad_max_score_next:下一个 anti-diagonal 的最大分数。
wire CID_prev_block,CID_prev_block_raw,H_converged_prev_block,H_converged_prev_block_raw;
assign {
CID_prev_block_raw,
H_converged_prev_block_raw,
CH_PE_prev_block_raw,
CI_PE_prev_block_raw,
H_prev_block_raw,
I_prev_block_raw,
ad_max_score_prev_block_raw
}=score_bram_data_out;
  • 从 score_bram 读出的数据分解成各个字段。

2.11 流水线寄存器​

sft_reg ##(.BW(CONV_SCORE_WIDTH),.DEPTH(3)) score_wr_delay(
.clk(clk),
.en(1),
.in(prev_block_to_write),
.out(score_bram_data_in));
  • score_wr_delay:把 prev_block_to_write 延迟 3 拍,写入 score_bram。
sft_w_rst ##(.DEPTH(3)) en_pipe(
.clk(clk),
.rst(rst),
.en(1),
.in(score_bram_wr_en),
.out(score_bram_wr_en_delayed)
);
  • en_pipe:写使能延迟 3 拍。
wire score_valid_delayed;
sft_w_rst ##(.DEPTH(3)) score_valid_pipe(
.clk(clk),
.rst(rst),
.en(1),
.in(init_out[NUM_PE-1]),
.out(score_valid_delayed)
);
assign score_bram_wr_en_ext=(score_bram_wr_en_delayed|score_bram_wr_en)&score_valid_delayed;
  • score_bram_wr_en_ext:写使能 = (延迟的写使能 | 当前写使能)& 数据有效。
always_ff @(posedge clk) begin
if(score_bram_wr_en_ext)
score_bram_addr_wr<=score_bram_addr_wr+1;
else
score_bram_addr_wr<=0;
end
  • score_bram 写地址递增。
logic past_score_bram_wr_en_ext;
parameter CONV_DONT_CARE=0;
parameter NU_DONT_CARE=5;
sft_w_rst ##(.DEPTH(1)) score_bram_wr_pipe(
.clk(clk),
.rst(rst),
.en(1),
.in(score_bram_wr_en_ext),
.out(past_score_bram_wr_en_ext)
);
  • past_score_bram_wr_en_ext:写使能延迟 1 拍,用于检测写结束。
logic [ LOG_MAX_TILE_SIZE-1:0 ] score_bram_valid_up_to;
always @(posedge clk ) begin
if(!score_bram_wr_en_ext&&past_score_bram_wr_en_ext)
score_bram_valid_up_to<=score_bram_addr_wr-1;
end
  • 当写使能下降沿时,记录最后一个有效地址。

2.12 score_bram 读控制​

always @(posedge clk ) begin
if(rst)
score_bram_rd_en <= 0;
else if (
(block && set_param[NUM_PE - 4]&&start_idx)||
(block && set_param[NUM_PE - 3])
) begin
score_bram_rd_en <= 1;
end else if(score_bram_addr_rd==score_bram_valid_up_to||set_param[0])
score_bram_rd_en <= 0;
end

逐行解释:

  • 复位时读使能清零。
  • 如果 block=1 且(set_param[NUM_PE-4] 且 start_idx,或 set_param[NUM_PE-3]),读使能置 1。
  • 如果读地址到达有效末尾,或 set_param[0],读使能清零。
logic past_score_bram_rd_en;
sft_w_rst ##(.DEPTH(1)) score_bram_rd_pipe(
.clk(clk),
.rst(rst),
.en(1),
.in(score_bram_rd_en),
.out(past_score_bram_rd_en)
);
wire not_last_droped_in_prev_block=past_score_bram_rd_en&&score_bram_rd_en;
  • not_last_droped_in_prev_block:上一个 block 的最右 PE 未被剪枝。

2.13 上一个 block 数据的流水线​

wire CID_prev_block_temp;
sft_reg ##(.DEPTH(1),.BW(1)) CID_pipe(.clk(clk),.en(1),.in(CID_prev_block_raw),.out(CID_prev_block_temp));
assign CID_prev_block=!not_last_droped_in_prev_block||CID_prev_block_temp;
  • CID_prev_block:上一个 block 的收敛状态。
wire H_converged_prev_block_temp;
sft_reg ##(.DEPTH(1),.BW(1)) H_converged_pipe(.clk(clk),.en(1),.in(H_converged_prev_block_raw),.out(H_converged_prev_block_temp));
assign H_converged_prev_block=!not_last_droped_in_prev_block||H_converged_prev_block_temp;
  • H_converged_prev_block:上一个 block 的 H 是否收敛。
logic prev_blk_valid;
sft_reg ##(.DEPTH(1),.BW(1)) prev_block_valid_pipe(.clk(clk),.en(1),.in(past_score_bram_rd_en),.out(prev_blk_valid));
  • prev_blk_valid:上一个 block 数据有效。
assign CH_PE_prev_block=past_score_bram_rd_en?CH_PE_prev_block_raw:CONV_DONT_CARE;
sft_reg ##(.DEPTH(1),.BW(REF_LEN_WIDTH+2)) CH_IDX_pipe(.clk(clk),.en(1),.in(CH_PE_prev_block),.out(CH_PE_prev_block_pipe));
sft_reg ##(.DEPTH(1),.BW(PE_WIDTH)) ad_max_pipe(.clk(clk),.en(1),.in(ad_max_score_prev_block_raw),.out(ad_max_score_prev_block));
assign CI_PE_prev_block=past_score_bram_rd_en?CI_PE_prev_block_raw:CONV_DONT_CARE;
assign H_prev_block=past_score_bram_rd_en?H_prev_block_raw:-INF;
assign I_prev_block=past_score_bram_rd_en?I_prev_block_raw:-INF;
  • 这些信号从 score_bram 读出后,根据有效标志选择真实值或 DONT_CARE。
assign last_PE_not_droped=(H_PE[NUM_PE-1]+xdrop_value)>=ad_max_score;
  • last_PE_not_droped:最右 PE 的 H + xdrop >= 当前最大分数,说明未被剪枝。

2.14 收敛条件​

assign H_converged=H_converged_this_block&&
H_converged_prev_block&&
past_marking&&
(!not_last_droped_in_prev_block||H_rd_value==CH_PE_prev_block_pipe);
  • H_converged:H 收敛 = 本 block 收敛 & 上一个 block 收敛 & 过了 marker & (上一个 block 最右 PE 被剪枝 或 H_rd_value == 上一个 block 的 CH)。
assign this_ad_converged=
H_converged&&
CID_prev_block&&
I_converged&&
D_converged&&
(I_rd_value==H_rd_value||I_rd_value==CONV_DONT_CARE||H_rd_value==CONV_DONT_CARE)&&
(D_rd_value==H_rd_value||D_rd_value==CONV_DONT_CARE||H_rd_value==CONV_DONT_CARE);
  • this_ad_converged:本 anti-diagonal 收敛 = H 收敛 & 上一个 block CID & I 收敛 & D 收敛 & I/H 收敛指针相同 & D/H 收敛指针相同。

2.15 收敛延迟寄存器​

logic [REF_LEN_WIDTH+1:0]H_rd_value_prev_ad;
logic H_converged_prev_ad;

always @(posedge clk ) begin
H_rd_value_prev_ad<=H_rd_value;
H_converged_prev_ad<=H_converged;
end
  • 把 H 收敛指针和 H 收敛标志延迟一拍。

2.16 对角线数据延迟​

logic signed [PE_WIDTH-1:0] diag_delayed;
logic [REF_LEN_WIDTH+1:0] diag_CH_delayed;
logic score_bram_loaded_first;
always @(posedge clk ) begin
if(rst)
score_bram_loaded_first<=0;
else
score_bram_loaded_first<=score_bram_rd_en&&score_bram_addr_rd==0;
end
always_ff @( posedge clk ) begin
if(score_bram_loaded_first)
diag_delayed<=H_prev_block;
else if(set_param[NUM_PE-2]&&block&&(!start_idx))
diag_delayed<=-INF;
end
always_ff @( posedge clk ) begin
if(score_bram_loaded_first)
diag_CH_delayed<=CH_PE_prev_block;
end
  • diag_delayed:上一个 block 的最后一个 H 分数,用于对角线初始化。
  • diag_CH_delayed:上一个 block 的最后一个 CH 收敛指针。

2.17 init_0_delayed​

logic init_0_delayed;
always @(posedge clk ) begin
if(STATE==SET_PARAM)
init_0_delayed<=0;
else if(init_out[0])
init_0_delayed<=1;
end
  • init_0_delayed:PE[0] 是否已初始化。

2.18 边界条件组合逻辑​

always_comb begin
curr_ref_idx = $signed(ref_idx_in[NUM_PE - 1] - 3) > 0 ? (ref_idx_in[NUM_PE - 1] - 3) : 0;
tb_bram_addr_reg = (STATE==TB) ? tb_bram_addr_out : tb_bram_addr;

C1 = (curr_ref_idx >= total_ref_length - 1) ? 1: 0;
C2 = (curr_query_length >= total_query_length - 1) ? 1 :0;
C3 = (!not_last_droped_in_prev_block) &&init_0_delayed &&(rd_value+xdrop_value<ad_max_score);
C4 = global_max_ad_idx>=convergence_detected_ad_idx;
C5 = this_ad_converged && (H_rd_value==H_rd_value_prev_ad) && past_marking&&H_converged_prev_ad ;
end

逐行解释:

  • curr_ref_idx:最后一个 PE 的 ref 坐标减去 3(因为 PE 阵列有流水线延迟)。
  • tb_bram_addr_reg:在 TB 状态用读地址,否则用写地址。
  • C1:ref 到达边界。
  • C2:query 到达边界。
  • C3:X-Drop 剪枝条件。
  • C4:收敛检测完成。
  • C5:收敛确认。

2.19 start_tb_from_xdrop 与 last_tile​

wire start_tb_from_xdrop;
assign start_tb_from_xdrop=global_max_ad_idx<=(marker+2);
always @(posedge clk ) begin
if(rst)
last_tile<=0;
else if(STATE==TB&&start_tb_from_xdrop)
last_tile<=1;
end
  • start_tb_from_xdrop:如果全局最大分数在 marker 附近,说明是 X-Drop 剪枝,不是收敛。
  • last_tile:在 TB 状态且从 X-Drop 开始时置 1。

2.20 收敛检测​

wire convergence_detected;
assign convergence_detected=C5&&(STATE==STREAM_REF)&&init_out[0]&&(!init_n || (!last_PE_not_droped))&&(!lower_bound_check);
  • convergence_detected:收敛检测 = C5 & STREAM_REF & PE[0] 已初始化 & (未初始化 或 最右 PE 被剪枝)& 未确定 lower bound。
always @(posedge clk ) begin
if(rst)
conv<=0;
else if(convergence_detected)
conv<=1;
end
  • conv:收敛标志寄存器。

2.21 traceback 初始化​

compute_tb_start ##(
.PE_WIDTH(PE_WIDTH),
.LOG_MAX_TILE_SIZE(LOG_MAX_TILE_SIZE),
.REF_LEN_WIDTH(REF_LEN_WIDTH)
) tb_init_inst(
.clk(clk),
.marker(marker),
.conv_value(global_max_conv_idx),
.conv_query_idx(conv_query_idx),
.conv_ref_idx(conv_ref_idx),
.conv_state(conv_tb_state)
);
  • 实例化 compute_tb_start,把 global_max_conv_idx 解码成 traceback 起点坐标和状态。
always @(posedge clk ) begin
if(rst)
convergence_detected_ad_idx<=INF;
else if (convergence_detected&&!conv)
convergence_detected_ad_idx<=curr_ad_idx;
end
  • convergence_detected_ad_idx:记录收敛检测时的 anti-diagonal 索引。
always @(posedge clk ) begin
if(set_param[0])
tb_bram_start_sub_ref_start[block_count-2]<=tb_bram_addr-lower_bound_value+(NUM_PE);
end
  • 记录每个 block 的 traceback 地址偏移。

2.22 序列转换​

ascii2nt ref_ascii2nt (
.ascii(ref_bram_data_out),
.complement(complement_ref_in),
.nt(ref_nt)
);

ascii2nt query_ascii2nt (
.ascii(query_bram_data_out),
.complement(complement_query_in),
.nt(query_nt)
);
  • 把 ref 和 query 的 ASCII 字符转成 3-bit nt。
nt2param ##(
.PE_WIDTH(PE_WIDTH)
) query_nt2param (
.nt(query_nt),
.in_param(in_param),
.out_param(out_param)
);

assign param = out_param;
assign {sub_A_in, sub_C_in, sub_G_in, sub_T_in} = query_oflow?{{4*PE_WIDTH}{1'b0}}:param;
  • nt2param 根据 query nt 选行,输出 out_param。
  • 如果 query 越界,替换分数全 0。

2.23 PE 阵列实例化​

logic [REF_LEN_WIDTH+2+REF_LEN_WIDTH+QUERY_LEN_WIDTH-1:0] max_val_to_sel[0:NUM_PE-1], selected_idx;
genvar i;
generate
for (i = 0; i < NUM_PE; i = i + 1)
begin: pe_gen
PE ##(
.PE_WIDTH(PE_WIDTH),
.DATA_WIDTH(DATA_WIDTH),
.NUM_BLOCK(NUM_BLOCK),
.NUM_PE(NUM_PE),
.LOG_NUM_PE(LOG_NUM_PE),
.REF_LEN_WIDTH(REF_LEN_WIDTH),
.QUERY_LEN_WIDTH(QUERY_LEN_WIDTH),
.PE_IDX(i),
.LOG_MAX_TILE_SIZE(LOG_MAX_TILE_SIZE)
) pe_affine (
.clk(clk),
.rst(rst),
.init_in(init_in[i]),
.set_param(set_param[i]),
.ref_in(ref_in[i]),
.param_valid_in(!query_oflow),
.sub_A_in(sub_A_in),
.sub_C_in(sub_C_in),
.sub_G_in(sub_G_in),
.sub_T_in(sub_T_in),
.sub_N_in(sub_N_in),
.gap_open_in(gap_open_in),
.gap_extend_in(gap_extend_in),
.INF(INF),
.block(block),
.diag_score(diag_delayed),
.diag_CH_score(diag_CH_delayed),
.start_idx(start_idx),
.marker(marker),
.ref_idx_in(ref_idx_in[i]),
.query_idx_in(query_idx_in[i]),
.D_init_in(D_init_in),
.H_init_in(H_init),
.H_PE_prev(H_PE_prev[i]),
.I_PE_prev(I_PE_prev[i]),
.CH_PE_prev(CH_PE_prev[i]),
.CI_PE_prev(CI_PE_prev[i]),
.init_out(init_out[i]),
.dir_out(dir_out[4*i + 3: 4*i]),
.ref_out(ref_out[i]),
.ref_idx_out(ref_idx_out[i]),
.query_idx_out(query_idx_out[i]),
.init_state(init_state),
.H_PE(H_PE[i]),
.I_PE(I_PE[i]),
.D_PE(D_PE[i]),
.CH_PE(CH_PE[i]),
.CI_PE(CI_PE[i]),
.CD_PE(CD_PE[i])
);
assign max_val_to_sel[i]={CH_PE[i],ref_idx_out[i],query_idx_out[i]};
end
endgenerate

逐行解释:

  • generate for 循环实例化 NUM_PE 个 PE。
  • 每个 PE 的 PE_IDX(i) 是它在阵列中的索引。
  • init_in[i]、set_param[i]、ref_in[i]、ref_idx_in[i]、query_idx_in[i]、H_PE_prev[i]、I_PE_prev[i]、CH_PE_prev[i]、CI_PE_prev[i] 都是每个 PE 独立的输入。
  • dir_out[4*i+3 : 4*i] 提取每个 PE 的 4-bit 指针。
  • max_val_to_sel[i] 打包 CH_PE、ref 坐标、query 坐标,用于 reduction tree。

2.24 reduction_tree_max​

wire [REF_LEN_WIDTH+1:0] max_CH_val;
wire [REF_LEN_WIDTH-1:0] cur_max_query_idx;
wire [QUERY_LEN_WIDTH-1:0] cur_max_ref_idx;
reduction_tree_max ## (
.PE_WIDTH(PE_WIDTH),
.SEL_WIDTH(REF_LEN_WIDTH+2+REF_LEN_WIDTH+QUERY_LEN_WIDTH),
.NUM_PE(NUM_PE),
.LOG_NUM_PE(LOG_NUM_PE)
) rd_tree_max (
.to_sel(max_val_to_sel),
.array(H_PE),
.reduction_value(rd_value),
.selected(selected_idx)
);
assign {max_CH_val,cur_max_ref_idx,cur_max_query_idx}=selected_idx;
  • rd_tree_max:找 H_PE 中的最大值 rd_value 和对应坐标。
  • max_CH_val:对应的 CH 收敛指针。
  • cur_max_ref_idx、cur_max_query_idx:对应的 ref 和 query 坐标。

2.25 reduction_tree_value × 3​

reduction_tree_value ## (
.PE_WIDTH(REF_LEN_WIDTH + 2),
.NUM_PE(NUM_PE),
.LOG_NUM_PE(LOG_NUM_PE)
) rd_tree_M (
.array(CH_PE),
.reduction_value(H_rd_value),
.reduction_bool(H_converged_this_block)
);

reduction_tree_value ## (
.PE_WIDTH(REF_LEN_WIDTH + 2),
.NUM_PE(NUM_PE),
.LOG_NUM_PE(LOG_NUM_PE)
) rd_tree_I (
.array(CI_PE),
.reduction_value(I_rd_value),
.reduction_bool(I_converged)
);

reduction_tree_value ## (
.PE_WIDTH(REF_LEN_WIDTH + 2),
.NUM_PE(NUM_PE),
.LOG_NUM_PE(LOG_NUM_PE)
) rd_tree_D (
.array(CD_PE),
.reduction_value(D_rd_value),
.reduction_bool(D_converged)
);
  • 三个 reduction tree 分别检查 H、I、D 的收敛指针是否全部相同。

2.26 下一个 tile 起点​

assign query_next_tile_addr=start_tb_from_xdrop?global_max_query_idx:conv_query_idx;
assign ref_next_tile_addr=start_tb_from_xdrop?global_max_ref_idx:conv_ref_idx;
assign next_tile_init_state=start_tb_from_xdrop?0:conv_tb_state;
  • 如果从 X-Drop 开始回溯,用全局最大分格子的坐标和状态 0(H)。
  • 否则用收敛点的坐标和状态。

2.27 traceback 实例化​

traceback ##(
.PE_WIDTH(PE_WIDTH),
.DATA_WIDTH(DATA_WIDTH),
.NUM_BLOCK(NUM_BLOCK),
.NUM_PE(NUM_PE),
.LOG_NUM_PE(LOG_NUM_PE),
.MAX_TILE_SIZE(MAX_TILE_SIZE),
.LOG_MAX_TILE_SIZE(LOG_MAX_TILE_SIZE),
.REF_LEN_WIDTH(REF_LEN_WIDTH),
.QUERY_LEN_WIDTH(QUERY_LEN_WIDTH),
.PARAM_ADDR_WIDTH(PARAM_ADDR_WIDTH),
.CONV_SCORE_WIDTH(CONV_SCORE_WIDTH),
.TB_DATA_WIDTH(TB_DATA_WIDTH)
) tb (
.clk(clk),
.rst(rst),
.tb_start(tb_start),
.start_query_idx(query_next_tile_addr),
.start_ref_idx(ref_next_tile_addr),
.start_tb_state(next_tile_init_state),
.tb_bram_addr_out(tb_bram_addr_out),
.tb_bram_data_out(tb_bram_data_out),
.addr_offset_rd_addr(block_rd_idx),
.addr_offset_rd_result(tb_bram_start_sub_ref_start[block_rd_idx]),
.tb_pointer(tb_pointer),
.tb_valid(tb_valid),
.first_tile(init_state==3),
.tb_done(tb_done)
);
  • 实例化 traceback 模块,从收敛点或最大分格子开始回溯。

2.28 traceback BRAM 写控制​

wire tb_bram_wr_en_next;
logic was_stream_ref;
always @(posedge clk ) begin
if(rst)
was_stream_ref<=0;
else
was_stream_ref<= (STATE==STREAM_REF);
end
assign tb_bram_wr_en_next=init_out[0]&&(was_stream_ref||(STATE==STREAM_REF))&&(!past_marking);
  • tb_bram_wr_en_next:PE[0] 已初始化 & (上一周期或当前是 STREAM_REF)& 未过 marker。
always @(posedge clk ) begin
if(rst)
tb_bram_wr_en<=0;
else
tb_bram_wr_en<=tb_bram_wr_en_next;
end

wire [TB_ADDR_WIDTH-1:0] tb_bram_wr_addr_next;
assign tb_bram_wr_addr_next=tb_bram_wr_en_next?tb_bram_addr+1:tb_bram_addr;
always @(posedge clk ) begin
if(rst)
tb_bram_addr<=-1;
else
tb_bram_addr<=tb_bram_wr_addr_next;
end
  • tb_bram_wr_en 和 tb_bram_addr 的写控制。

2.29 PE 间 systolic 连接​

generate
for (i = 1; i < NUM_PE; i = i + 1)
begin: systolic_array_connections
assign init_in[i] = (STATE==STREAM_REF_CONTINUE)?0:init_out[i-1];
assign ref_in[i] = ref_out[i-1];
assign ref_idx_in[i] = ref_idx_out[i-1];
assign query_idx_in[i] = query_idx_out[i-1];
assign H_PE_prev[i] = H_PE[i-1];
assign I_PE_prev[i] = I_PE[i-1];
assign CH_PE_prev[i] = CH_PE[i-1];
assign CI_PE_prev[i] = CI_PE[i-1];
end
endgenerate

逐行解释:

  • init_in[i]:在 STREAM_REF_CONTINUE 状态清零,否则来自 PE[i-1] 的 init_out。
  • ref_in[i]:来自 PE[i-1] 的 ref_out。
  • ref_idx_in[i]:来自 PE[i-1] 的 ref_idx_out。
  • query_idx_in[i]:来自 PE[i-1] 的 query_idx_out。
  • H_PE_prev[i]:来自 PE[i-1] 的 H_PE。
  • I_PE_prev[i]:来自 PE[i-1] 的 I_PE。
  • CH_PE_prev[i]:来自 PE[i-1] 的 CH_PE。
  • CI_PE_prev[i]:来自 PE[i-1] 的 CI_PE。

2.30 PE[0] 的特殊连接​

always_ff @( posedge clk ) begin
I_PE_prev[0]<=block? I_prev_block : -INF;
end
assign D_init_in = -INF;
assign init_in[0]=(STATE==STREAM_REF);
  • I_PE_prev[0]:后续 block 用上一个 block 的 I,否则 −∞-\infty。
  • D_init_in:固定为 −∞-\infty。
  • init_in[0]:在 STREAM_REF 状态为 1。

2.31 H_init 初始化​

wire [PE_WIDTH-1:0 ] boundary_init_H_score_next;
assign boundary_init_H_score_next=H_init+gap_extend_in;
always_ff @( posedge clk ) begin
if(STATE==STREAM_REF_START)
H_init<=(block||init_state!=3)?-INF:gap_open_in;
else if(STATE==STREAM_REF)
H_init<=(block||init_state!=3)?-INF:boundary_init_H_score_next;
end
  • H_init:初始 H 分数。
    • 第一个 block 且 init_state==3(标准对角初始化):H_init = gap_open;
    • 之后每周期增加 gap_extend;
    • 其他情况 −∞-\infty。

2.32 H_PE_prev[0] 初始化​

always_ff @( posedge clk ) begin
if(STATE==STREAM_REF_START)
H_PE_prev[0] <= block ? H_prev_block : (init_state!=3?-INF:gap_open_in);
else if(STATE==STREAM_REF)
H_PE_prev[0] <= block ? H_prev_block : (init_state!=3?-INF:boundary_init_H_score_next);
end
  • H_PE_prev[0]:PE[0] 的左邻 H(实际上来自上一个 block 或初始值)。

2.33 CH/CI_PE_prev[0] 初始化​

always_ff @( posedge clk) begin
if(STATE==STREAM_REF||STATE==STREAM_REF_START)
CH_PE_prev[0]<= block? CH_PE_prev_block:CONV_DONT_CARE;
end

always_ff @( posedge clk) begin
if(STATE==STREAM_REF||STATE==STREAM_REF_START)
CI_PE_prev[0]<= block? CI_PE_prev_block:CONV_DONT_CARE;
end
  • CH_PE_prev[0]、CI_PE_prev[0]:PE[0] 的左邻收敛指针。

2.34 ad_max_score 更新​

always_comb begin
cur_ad_max_score=rd_value;
if(block&&not_last_droped_in_prev_block) begin
if(ad_max_score_prev_block>cur_ad_max_score)
cur_ad_max_score=ad_max_score_prev_block;
end
end
assign ad_max_score_next=(cur_ad_max_score>ad_max_score)?cur_ad_max_score:ad_max_score;
always_ff @( posedge clk ) begin
if(rst||STATE==STREAM_REF_CONTINUE)
ad_max_score<=0;
else if(init_out[0])
ad_max_score<=ad_max_score_next;
end
  • cur_ad_max_score:当前最大值,取 rd_value 和 ad_max_score_prev_block 的最大。
  • ad_max_score_next:更新后的最大值。
  • ad_max_score:寄存器。

2.35 score_bram 读地址​

always_ff @(posedge clk) begin
if (score_bram_rd_en) begin
score_bram_addr_rd <= score_bram_addr_rd + 1;
end else
score_bram_addr_rd <=0;
end
  • score_bram 读地址递增。

2.36 ref_in[0] 赋值​

assign ref_in[0] =ref_oflow?NU_DONT_CARE:ref_nt;
  • PE[0] 的 ref 输入:ref 越界时用 NU_DONT_CARE,否则用 ref_nt。

2.37 状态机数据路径​

always_ff @(posedge clk) begin : state_description
if (rst) begin
block <= 0;
init_n <= 0;
set_param <= 0;
curr_query_length <= 0;
curr_ref_length <= 0;
start_idx <= 0;
lower_bound_check <= 0;
lower_bound_value <= 0;
block_count <= 0;
ref_bram_addr <= 0;
query_bram_addr <= 0;
rstb <= 0;
regceb <= 0;
score_bram_wr_en <= 0;
tb_bram_data_in <= 0;
global_max_score <= 0;
global_max_ad_idx<=0;
query_idx_in[0] <= 0;
ref_idx_in[0] <= 0;
tb_start <= 0;
end

复位分支:所有寄存器清零。

else begin
regceb <= 1;
init_n <= init_out[NUM_PE - 2] & init_out[0];
tb_bram_data_in <= dir_out;
  • regceb <= 1:始终使能 score_bram 输出寄存器。
  • init_n:PE[NUM_PE-2] 和 PE[0] 都已初始化。
  • tb_bram_data_in <= dir_out:traceback 数据写入。
case (STATE)
WAIT: begin
end
  • WAIT 状态:什么都不做。
READ_PARAM: begin
sub_N_in <= in_param[3*PE_WIDTH-1-:PE_WIDTH];
gap_open_in <= in_param[2*PE_WIDTH-1-:PE_WIDTH];
gap_extend_in <= in_param[PE_WIDTH-1:0];

ref_bram_addr <= 0;
query_bram_addr <= 0;

block_count <= block_count + 1;
end
  • READ_PARAM:从 in_param 提取 sub_N、gap_open、gap_extend。
  • 复位 ref/query BRAM 地址。
  • block_count 加 1。
SET_PARAM: begin
if (!set_param) begin
set_param <= 1;
end
else begin
set_param <= set_param << 1;
end
query_bram_addr <= query_bram_addr + 1;
curr_query_length <= curr_query_length + 1;
end
  • SET_PARAM:set_param 移位寄存器初始化并左移。
  • query_bram_addr 和 curr_query_length 递增。
STREAM_REF_START: begin
set_param <= 0;
lower_bound_check <= 0;
curr_ref_length <= curr_ref_length + 1;
ref_bram_addr <= ref_bram_addr + 1;
ref_idx_in[0] <= ref_idx_in[0] + 1;
end
  • STREAM_REF_START:清 set_param,复位 lower_bound_check。
  • ref 长度、地址、PE[0] ref 坐标递增。
STREAM_REF: begin
curr_ref_length <= curr_ref_length + 1;
ref_bram_addr <= ref_bram_addr + 1;
ref_idx_in[0] <= ref_idx_in[0] + 1;

if (!lower_bound_check && init_n && last_PE_not_droped) begin
lower_bound_check <= 1;
lower_bound_value <= curr_ref_idx;
end

if ($signed(global_max_score) <= $signed(rd_value)) begin
global_max_score <= rd_value;
global_max_ref_idx <= cur_max_ref_idx-1;
global_max_query_idx <= cur_max_query_idx-1;
global_max_ad_idx<=curr_ad_idx;
global_max_conv_idx<=max_CH_val;
end

if (init_n) begin
if (!score_bram_wr_en && !lower_bound_check && last_PE_not_droped) begin
score_bram_wr_en <= 1;
end
end
end

逐行解释:

  • 更新 ref 长度、地址、PE[0] ref 坐标。
  • 如果未确定 lower bound 且 init_n 且最右 PE 未剪枝,记录 lower_bound_value。
  • 如果当前 rd_value 超过全局最大分数,更新全局最大分数、坐标、AD 索引、收敛指针。
  • 如果 init_n 且未开始写 score_bram 且未确定 lower bound 且最右 PE 未剪枝,开始写 score_bram。
STREAM_REF_CONTINUE: begin
block <= 1;
start_idx <= lower_bound_value;
ref_bram_addr<=lower_bound_value;
ref_idx_in[0] <= lower_bound_value;
curr_ref_length <= lower_bound_value;
query_idx_in[0] <= curr_query_length;
block_count <= block_count + 1;
score_bram_wr_en <= 0;
end
  • STREAM_REF_CONTINUE:block 切换到 1。
  • 重置 ref 相关信号为 lower_bound_value。
  • query 保持连续。
  • block_count 递增。
  • 清 score_bram 写使能。
STREAM_REF_STOP: begin
end

STREAM_REF_DONE: begin
end

DONE: begin
end

TB: begin
tb_start <= 1;
end

EXIT: begin
end

endcase

end
end
  • STOP/DONE/EXIT:空操作。
  • TB:启动 traceback。
wire load_new_seq;
assign load_new_seq=(STATE==STREAM_REF_START)&&block_count;
assign stop=tb_done;
  • load_new_seq:在 STREAM_REF_START 且 block_count 非零。
  • stop = tb_done。

2.38 状态机​

always_ff @(posedge clk) begin : state_machine
if (rst)
STATE <= WAIT;

else begin
case (STATE)
WAIT: begin
if (start) begin
STATE <= READ_PARAM;
end
end

READ_PARAM: begin
STATE <= SET_PARAM;
end

SET_PARAM: begin
if (set_param[NUM_PE - 2])
STATE <= STREAM_REF_START;
end

STREAM_REF_START: begin
STATE <= STREAM_REF;
end

STREAM_REF: begin
if(C4)
STATE<=DONE;
else if ( (ref_oflow&& ref_in[NUM_PE-1]==NU_DONT_CARE) ||C3) begin
STATE <= (lower_bound_check&&!query_oflow)?STREAM_REF_CONTINUE:DONE;
end
else begin
STATE <= STREAM_REF;
end
end

STREAM_REF_CONTINUE: begin
STATE <= SET_PARAM;
end

STREAM_REF_STOP: begin
STATE <= EXIT;
end

STREAM_REF_DONE: begin
end

DONE: begin
STATE <= DONE2;
end

DONE2:STATE<=TB;

TB: begin
if (tb_done == 1) begin
STATE <= EXIT;
end
end

EXIT: begin
end

endcase
end
end
assign commit=STATE==SET_PARAM;
assign traceback=STATE==TB||STATE==WAIT||STATE==EXIT;
endmodule

逐状态解释:

  • WAIT:start 为 1 时进入 READ_PARAM。
  • READ_PARAM:进入 SET_PARAM。
  • SET_PARAM:set_param 移到 NUM_PE-2 时进入 STREAM_REF_START。
  • STREAM_REF_START:进入 STREAM_REF。
  • STREAM_REF:
    • C4(收敛检测完成)→ DONE;
    • ref 越界 或 C3(X-Drop 剪枝)→ 如果 lower_bound_check 且 query 未越界,进入 STREAM_REF_CONTINUE,否则 DONE;
    • 否则继续 STREAM_REF。
  • STREAM_REF_CONTINUE:进入 SET_PARAM。
  • STREAM_REF_STOP:进入 EXIT。
  • DONE:进入 DONE2。
  • DONE2:进入 TB。
  • TB:tb_done 时进入 EXIT。
  • EXIT:空操作。

输出信号:

  • commit = STATE==SET_PARAM;
  • traceback = STATE==TB || STATE==WAIT || STATE==EXIT。

模块三:sft_reg​

module sft_reg##(parameter BW = 10, DEPTH=10) (input clk, en, input [BW-1:0] in, output [BW-1:0] out);
logic [BW-1:0] content[DEPTH-1:0];
int idx;
always_ff @( posedge clk ) begin
if(en) begin
content[0]<=in;
for (idx = 1; idx<DEPTH; idx++) begin
content[idx]<=content[idx-1];
end
end
end
assign out=content[DEPTH-1];
endmodule

逐行解释:

  • content:DEPTH 个 BW 位寄存器。
  • 每个周期,content[0] 捕获 in,content[i] 捕获 content[i-1]。
  • 输出是 content[DEPTH-1],即延迟 DEPTH 拍。

模块四:sft_w_rst​

module sft_w_rst##(DEPTH=10) (input clk, input en, input rst, input in, output out);
logic [DEPTH-1:0] data;
always @(posedge clk ) begin
if(rst)
data<=0;
else if(en)
if(DEPTH>1)
data<={data[DEPTH-2:0],in};
else
data<=in;
end
assign out=data[DEPTH-1];
endmodule

逐行解释:

  • data:DEPTH 位移位寄存器。
  • 复位时清零。
  • 否则左移,in 进入最低位。
  • 输出是最高位 data[DEPTH-1],即延迟 DEPTH 拍。

总结​

PE_Array.sv 包含四个模块:

模块作用
compute_tb_start把收敛指针解码成 traceback 起点
PE_Array主体,包含状态机、PE 阵列、reduction tree、traceback 控制
sft_reg带使能的移位寄存器
sft_w_rst带复位和使能的移位寄存器

PE_Array 的核心流程:

  1. WAIT → READ_PARAM → SET_PARAM:加载参数,流式输入 query;
  2. STREAM_REF_START → STREAM_REF:流式输入 ref,PE 阵列计算;
  3. STREAM_REF_CONTINUE:block 切换;
  4. DONE → DONE2 → TB:收敛检测完成,启动 traceback;
  5. EXIT:完成,输出下一个 tile 起点。

关键机制:

  • Block 切换:通过 lower_bound_value 确定下一个 block 的起点;
  • 收敛检测:三个 reduction tree 检查 H/I/D 收敛指针是否全部相同;
  • Traceback 起点:如果从 X-Drop 开始,用全局最大分格子;如果从收敛点开始,用 global_max_conv_idx;
  • 下一个 tile 起点:query_next_tile_addr 和 ref_next_tile_addr 由收敛点或最大分格子决定。