目前有基于booth算法的乘法器模块:
假设乘法器名称:
mul_top.v
mul_top( valid,ready,//输入握手
clk,reset,
data1,data2,out,//输入两个数,输出乘积
opcode,//不同的指令来指定位宽、符号的条件
instruction_id,//指令id,不需要formal去验证
outputvalid,outputready)//输出握手
//假设cycle delay是4个cycle。
假设乘法器框架图如下(从网上找的图):
乘法器的公式推理就不多放了,大概来说就是将多个子乘积结果相加。
基于booth的乘法器输出结果的cycle delay一般是固定的,c2rtl的脚本中写assertion时会比较简单。(有的其他计算模块的cycle delay不固定,比如基于srt的除法模块,后续讨论)
首先需要准备golden的c model:
假设名称为mul.c
#include "jasperc.h"
#include "stdint.h"
int main() {
unsigned long int a, b,opcode;
unsigned long int out0;
unsigned long int out1;
JG_INPUT(a);
JG_INPUT(b);
JG_INPUT(opcode);
if(opcode ==1){
out0 = a * b;
JG_OUTPUT (out0);
}
else {
out1 = bit32result(a,b);
JG_OUTPUT (out1);
}
}
int bit32result(int a,int b){
//......
}
这部分主要工作就是添加input,output的一些宏定义就可以了(在比较复杂的场景中可能需要if语句,这部分输出的宏定义需要额外考虑)。
然后需要编写tcl脚本文件:
文件中规定了要分析的模块、clock、reset、断言、验证辅助语句以及工具配置。
clear -all
check_c2rtl -compile -spec mul.c //编译c model,也可以在这里添加c lib
check_c2rtl -analyze -imp -sv mul_top.v
check_c2rtl -elaborate -imp -top mul_top //编译组建 verilog
check_c2rtl -setup
clock mul_top.clk
reset mul_top.reset
//在这里没有添加IO映射,直接用assertion代替。
assume -name egnore_id {instruction_id==0} //忽略不关注的信号
assert {valid&ready |-> a==mul_top.data1 & b==mul_top.data2 & mul_top.opcode==opcode} //代替IO映射
assert -name out0 {outputvalid&outputready&opcode==1 |-> out==$past(out0,4)} //检查opcode==1分支的结果
assert -name out1 {outputvalid&outputready&opcode==2 |-> out==$past(out1,4)} //检查opcode!=1分支的结果
//可能由于乘法器比较复杂,c2rtl跑不出来,就需要给它添加一些辅助逻辑:
virtual_net inner_result -width 64 -expression {mul_top.some_inner_value1 * mul_top.some_inner_value2}
virtual_net adder_tree_out -width 64 -expression {
//booth算法中的加法树部分的中间结果相加。
}
assert -helper -name adder_tree {##2 adder_tree_out == inner_result}//假设输入产生后两个cycle之后,这个式子成立。
check_c2rtl -map -spec {a} -imp {mul_top.data1}
check_c2rtl -map -spec {b} -imp {mul_top.data2}
check_c2rtl -map -spec {opcode} -imp {mul_top.opcode}
//添加proof_structure来控制验证步骤:
proof_structure -init IMUL \
-from <embedded> \
-copy_assumes \
-copy { out0 out1 adder_tree }
proof_structure -create assume_guarantee \
-from IMUL \
-op_name asm_gnt \
-imp_name {helpers final_mul } \
-property {{adder_tree } {out0 out1}}
prove -bg -property helpers::adder_tree -engine Hp
prove -bg -property
set_engineWL_processes 12
prove -bg -property {final_mul::out0 final_mul::out1} -engine WHp
//这里用了印度老外的脚本,他们具体写了啥,我也不清楚,技术还没掌握在自己手里 MD
//source multiplier_engines.tcle
//prove -bg -property two_helpers::pp_encoding -engine "$mul_engine7 $mul_engine8"
这里看到,每个if分支都会有单独的输出,在添加assertion的时候需要每个if都给写一个assertion。
virtual_net 通过简化rtl逻辑来减少验证空间
proof_structure 来控制验证逻辑