is_rvc信号判断指令是否为riscv的压缩指令
rvc开头的均为对压缩指令的scan
rvi开头的与之相反
rvi_jump_o
判断指令是否为jal类
rvi_jalr_o
判断指令是否为jalr类
rvi_branch_o
判断指令是否为B类
rvi_call_o
若指令为jal或者jalr指令且rd为x1或x5则为真
rvi_return_o
若指令为jalr指令且rs1是x1或x5且rd不是x1则为真
BHT——Branch History Table,顾名思义,这是记录分支历史信息的表格,用于判定一条分支指令是否token。这个表格的索引是指令PC值,一般就用指令的后12位作为BHT表格的索引。在BHT中用1bit位记录分支是否跳转不够准确,一般就用2bit位记录分支是否跳转:例如11和10表示这条分支会跳转;01和00表示分支不会跳转。这个2bit计数器叫做饱和计数器。
BTB——branch target buffer用于记录一条分支指令的跳转地址,BTB一般很小,就32项或者64项。由于这个BTB容量小,并且其用于是记录分支指令的跳转地址,因此,如果这条指令不跳转,即其下一条指令就是PC+4,则不会在BTB中记录的。
基于BTB和BHT的分支预测:
1)在取指阶段利用PC寻址BTB,如果命中,则说明这是一条跳转指令,利用从BTB中获取到的地址去取icache;
2)由于BTB中保存的内容不够多,因此BHT的准确率更高,这个时候索引BHT表格,如果发现BHT也跳转,则说明这条指令预测是跳转的;如果BHT不跳转,则说明不跳转,这个时候就取消BTB中的指令地址,重新PC+4去取icache。
btb信号与变量解释:
INSTR_PER_FETCH:每次最多可以取多少条指令,由于取指宽度为32位,且ariane支持压缩指令(16位),因此最多可以取两条指令
NR_ROWS*INSTR_PER_FETCH就是btb的规模
btb_prediction_o:btb.sv的唯一输出信号,其结构如下(一位有效位和预测目标地址):
typedef struct packed {
logic valid;
logic [riscv::VLEN-1:0] target_address;
} btb_prediction_t;
btb用变量index作为匹配指令与预测的目标地址的索引,位数等于log2(NR_ROWS),从指令尾部ROW_ADDR_BITS+OFFSET处开始截取
assign index=vpc_i[PREDICTION_BITS-1:ROW_ADDR_BITS+OFFSET];
如果发生一次不命中,则用信号btb_update_i更新btb,valid位置1,预测的目标地址改为btb_update_i.target_address,该数据结构如下:
typedef struct packed {
logic valid;
logic [riscv::VLEN-1:0] pc; // update at PC
logic [riscv::VLEN-1:0] target_address;
} btb_update_t;
bht信号与变量解释:
bht_prediction_o是唯一的输出信号,包含一位valid,一位taken。若saturation_counter状态为为10或11时,taken为1,表示分支会跳转。
typedef struct packed {
logic valid;
logic taken;
} bht_prediction_t;
bht的索引index同btb。
以下为2bit动态预测器工作原理:
typedef struct packed {
logic valid;
logic [riscv::VLEN-1:0] pc; // update at PC
logic taken;
} bht_update_t;
taken表示分支实际上是否跳转。
ras是返回地址栈,用于为jal指令提供返回地址。
data_o是唯一的输出变量,包含有效位valid和返回地址,其结构如下:
typedef struct packed {//连续的地址空间,需要packed
logic valid;
logic [riscv::VLEN-1:0] ra;
} ras_t;
输出信号data_o等于stack_q[0],也就是返回地址栈的栈顶。
当输入信号push_i为1时,则将栈顶置为data_i,valid位置1,其余位顺序后移;
当输入信号pop_i为1时,则将栈底置为0,valid位置0,其余位顺序前移;
当同时pop,push时,认为先pop再push,只需要将栈顶置为data_i,valid位置1。
根据以上几个文件的代码,可以看出,aiane一般同时定义两个结构xx_d和xx_q,比如stack_q、stack_d,先用信号更新d,当时钟沿到来时,将d赋值给q。
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
stack_q <= '0;
end else begin
stack_q <= stack_d;
end
end