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):- 在反对角线上,;
- 所以 ;
conv_marker==3时(marker 前一格),再多减 1。
case (conv_marker):0(H)→conv_state = 02(D)→conv_state = 11(I)→conv_state = 23(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_BLOCK | tile 内 block 数量 |
NUM_PE | PE 阵列宽度 |
MAX_TILE_SIZE | tile 最大尺寸 |
CONV_SCORE_WIDTH | score_bram 数据宽度(conv_check + CH + CI + H + I + ad_max) |
TB_DATA_WIDTH | traceback BRAM 数据宽度 = 4*NUM_PE |
TB_ADDR_WIDTH | traceback 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_param | 13 个打分参数(替换矩阵 + 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_addr | BRAM 读地址 |
ref_bram_data_out / query_bram_data_out | BRAM 读出的 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, regceb | score_bram 的复位和输出寄存器使能 |
score_bram_wr_en_ext | score_bram 写使能 |
score_bram_rd_en | score_bram 读使能 |
score_bram_data_in/out | score_bram 数据 |
score_bram_addr_wr/rd | score_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_en | traceback BRAM 写使能 |
tb_bram_data_in | traceback BRAM 写入数据(4-bit dir × NUM_PE) |
tb_bram_data_out | traceback BRAM 读出数据 |
tb_bram_addr_reg | traceback 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_value | X-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_CONTINUE | block 结束,准备下一个 block |
STREAM_REF_DONE | ref 流式完成(未使用) |
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_nt | ref 碱基(3-bit nt) |
query_nt | query 碱基(3-bit nt) |
block | 是否是后续 block |
param / out_param | nt2param 的输入输出 |
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_in | gap 罚分 |
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_idx | traceback 地址偏移读索引 |
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_init | H 状态初始值(寄存器) |
D_init_in | D 状态初始值(固定为 -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_array | reduction 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_value | reduction tree 归约后的 H 收敛指针 |
I_rd_value | reduction tree 归约后的 I 收敛指针 |
D_rd_value | reduction tree 归约后的 D 收敛指针 |
rd_value | reduction 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_count | block 计数器 |
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 | 收敛标志(寄存器) |
C1 | ref 边界条件 |
C2 | query 边界条件 |
C3 | X-Drop 剪枝条件 |
C4 | 收敛检测完成条件 |
C5 | 收敛确认条件 |
query_oflow | query 越界 |
ref_oflow | ref 越界 |
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_start | traceback 启动 |
tb_state | traceback 状态(未使用) |
tb_bram_addr_out | traceback BRAM 读地址 |
tb_bram_addr | traceback BRAM 写地址 |
tb_done | traceback 完成 |
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,否则 。D_init_in:固定为 。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; - 其他情况 。
- 第一个 block 且
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&¬_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 的核心流程:
WAIT→READ_PARAM→SET_PARAM:加载参数,流式输入 query;STREAM_REF_START→STREAM_REF:流式输入 ref,PE 阵列计算;STREAM_REF_CONTINUE:block 切换;DONE→DONE2→TB:收敛检测完成,启动 traceback;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由收敛点或最大分格子决定。