本项目可以将Verilog代码(RTL级)转为晶体管级SourcePawn电路网表,支持自定义工艺库、自定义逻辑门子电路网表、自定义电路/晶体管参数、RTL/Netlist混合综合、生成RTL Testbench/网表Transient Analysis等功能。
如果你也被复旦微电子学院数字集成电路课折磨,麻烦点个star,本程序将帮你脱离苦海。
目前支持以下特性:
支持wire类型的assign,支持常量,支持线网总线,,支持~
&
|
^
运算,支持括号解析,暂不支持?:
三元运算符与{}
拼接运算
例如:
assign carry_ulp[64:1] = (g | p & carry_ulp[63:0]) & 64'hFFFFFFFFFFFFFFFF;
支持模块定义,支持实例化与数组实例化,暂不支持genfor,输入输出类型需要在定义时声明
例如:
module top(input [3:0]in,output [3:0]out);
test test_inst[3:0](.a(in[3:0]),.b(4'h7),.out(out));
endmodule
module test(input a,b,output out);
assign out = a & b;
endmodule
RTL综合结果默认是各个二输入门的连接结果,如果想自己实现多输入或者某个特定晶体管组合逻辑,可以使用编译指令对 `celldefine
和 `endcelldefine
将一个模块标记为cell模块,程序会自动检索输入目录下的sp文件中是否存在和模块同名的subckt子电路,子电路的输入输出顺序需和RTL代码中的顺序一致,线网总线用{$netName}_{$index}表示,顺序为LSB至MSB。
例如在项目目录下,有如下示例文件:
./examples/
├── adders.v
├── subckt.sp
└── top.v
adders.v
定义了半加器模块hadd
和1位全加器模块add1
,其中半加器模块hadd
被编译指令对 `celldefine
和 `endcelldefine
标记为cell模块:
//adders.v
module add1 (input a,
input b,
input cin,
output sum,
output cout);
wire s,c1,c2;
hadd hadd1(.a(a),.b(b),.s(s),.c(c1));
hadd hadd2(.a(s),.b(cin),.s(sum),.c(c2));
assign cout = c1 | c2;
endmodule
`celldefine
module hadd(input a,input b,output s,output c);
assign s = a ^ b;
assign c = a & b;
endmodule
`endcelldefine
subckt.sp
定义了上文hadd
模块的子电路,由于此模块被标记为cell模块,在综合时会综合为sp网表文件中的同名子电路:
*subckt.sp
.SUBCKT hadd a b s c
Mp1 buf1 a VDD VDD PMOS_3P3 L=LP W=2*WP
Mp2 out_buf b buf1 buf1 PMOS_3P3 L=LP W=2*WP
Mn1 out_buf a GND GND NMOS_3P3 L=LN W=WN
Mn2 out_buf b GND GND NMOS_3P3 L=LN W=WN
XAND a b c AND
Mp3 buf out_buf VDD VDD PMOS_3P3 L=LP W=2*WP
Mp4 s c buf buf PMOS_3P3 L=LP W=2*WP
Mn3 s out_buf GND GND NMOS_3P3 L=LN W=WN
Mn4 s c GND GND NMOS_3P3 L=LN W=WN
.ENDS hadd
默认综合使用./src/lib/model/SC
里预先提供的静态互补逻辑的网表,包含INV.sp
,AND.sp
,OR.sp
,XOR.sp
,已考虑NMOS与PMOS的尺寸规划。有兴趣可以自己新建文件夹写自己的门模型,如有比逻辑/动态逻辑/DCVSL等,并使用形如命令行参数--model SC
来指定你的模型库。
默认使用./src/lib/process
里预先提供的sm046005-1j.hspice
0.35um工艺库,默认工艺角typical,也可以在里面放你自己的工艺库并使用形如命令行参数--process sm046005-1j.hspice
指定。
目前支持指定VDD电压,使用形如--voltage 1.8V
参数指定,默认为3.3V
默认晶体管尺寸$L_P=L_N=0.35\mu m,W_P=3.5\mu m,W_N=1\mu m$,支持使用形如--WP 2u
的命令进行修改
为了仿真电路输出遇到的扇入负载,可使用形如--capacitorLoad 1pF
指定输出负载电容为$1pF$(如无指定默认为$0.01pF$),
可根据仿真设置自动生成网表激励电压源,会在output/testbench
文件夹下生成RTL Testbench与适用于ModelSim的auturun.tcl
。如果环境变量中设置了HSpice/wv/ModelSim则会自动运行,如果没有也可以手动使用HSPUI选择网表运行,并且使用命令行运行ModelSim脚本。
$ vsim -do ./autorun.tcl
使用-t sweep
参数,默认扫描所有可能的输入,但是仿真时间会很长,可使用--tbIterMax 10
指定每个信号总线需要仿真的最大样本数,默认最大为$2^{30}$(否则会发生整型溢出)。
使用形如-t 1A6
采用指定十六进制输入作为仿真激励。本例子中顶层模块输入依次为a[3:0]
b[3:0]
cin
,0x1A6 = 0b1101_0011_0,相当于指定输入a=4'b1101
b=4'b0011
cin=1'b0
,进行某个特定输入下的仿真,多个输入可以用逗号隔开。
使用-t random
采用随机激励仿真,配合形如--tbIterMax 100
的参数指定仿真样本数(此处为100)。
有时候生成的网表功能不一定和RTL代码一样,请提交issue。
缓存文件夹output/tmp
中有模块与线网展开后的Verilog文件,可用于检查解析过程是否有误。可添加--clearCache
删除临时文件缓存。
使用-v
或--verbose
观察详细的命令行输出,可以看到综合解析的过程,检查是否解析有误。
在项目目录下,有如下示例文件:
./examples/
├── adders.v
├── subckt.sp
└── top.v
adders.v
定义了半加器模块hadd
和1位全加器模块add1
,其中半加器模块hadd
被编译指令对 `celldefine
和 `endcelldefine
标记为cell模块:
//adders.v
module add1 (input a,
input b,
input cin,
output sum,
output cout);
wire s,c1,c2;
hadd hadd1(.a(a),.b(b),.s(s),.c(c1));
hadd hadd2(.a(s),.b(cin),.s(sum),.c(c2));
assign cout = c1 | c2;
endmodule
`celldefine
module hadd(input a,input b,output s,output c);
assign s = a ^ b;
assign c = a & b;
endmodule
`endcelldefine
subckt.sp
定义了上文hadd
模块的子电路,由于此模块被标记为cell模块,在综合时会综合为sp网表文件中的同名子电路:
*subckt.sp
.SUBCKT hadd a b s c
Mp1 buf1 a VDD VDD PMOS_3P3 L=LP W=2*WP
Mp2 out_buf b buf1 buf1 PMOS_3P3 L=LP W=2*WP
Mn1 out_buf a GND GND NMOS_3P3 L=LN W=WN
Mn2 out_buf b GND GND NMOS_3P3 L=LN W=WN
XAND a b c AND
Mp3 buf out_buf VDD VDD PMOS_3P3 L=LP W=2*WP
Mp4 s c buf buf PMOS_3P3 L=LP W=2*WP
Mn3 s out_buf GND GND NMOS_3P3 L=LN W=WN
Mn4 s c GND GND NMOS_3P3 L=LN W=WN
.ENDS hadd
top.v
定义了top_module,功能为4位级联加法器,示例化了4个1位加法器:
module top_module(input [3:0] a,b,
input cin,
output[3:0] sum,
output cout);
wire [3:0]carry_out,carry_in;
assign cout = carry_out[3];
assign carry_in[0] = cin;
assign carry_in[3:1] = carry_out[2:0];
add1 add[3:0](.a(a),.b(b),.cin(carry_in),.cout(carry_out),.sum(sum));
endmodule
在命令行中运行
$ perl ./src/main.pl ./examples --ignoreFiles tb.v --top top.v -o top.sp --process sm046005-1j.hspice --voltage 3.3 --model SC -t=sweep --tbIterMax 16 --timescale us --tbStep 0.01 --tbPulse 5 --capacitorLoad 1pF --WP 2u --clearCache -v
./src/main.pl
为主程序,
./examples
指定输入目录为./examples
,
--ignoreFiles tb.v
综合时忽略文件tb.v,多个文件用逗号隔开,
--top top.v
指定top_module所在的文件为top.v
(若无此参数则会自动选取输入文件夹内唯一的.v文件或名字带有top的.v文件),会自动指定此文件内名字内带有top的模块作为顶层模块,
--process sm046005-1j.hspice
指定工艺库为sm046005-1j.hspice
(如无指定则默认sm046005-1j.hspice),
--voltage 3.3
指定$V_{DD}=3.3V$(如无指定则默认$V_{DD}=3.3V$),
--model SC
指定门模块模型为SC
(静态互补)(如无指定则默认SC),
-t=sweep
指定需要生成瞬态分析的激励源和RTL仿真激励文件(生成在${inputPath}/output/testbench/testbench.v中),生成模式为扫描所有可能输入模式(也可以使用-t 1A6
,0x1A6 = 0b1101_0011_0,相当于指定输入a=4'b1101 b=4'b0011 cin=1'b0,跑某个特定输入下的仿真,多个输入可以用逗号隔开;也可以使用-t random
配合--tbIterMax 100
随机生成100组数据)
--tbIterMax 16
设定RTL仿真激励文件中每个输入信号最大仿真种类数为16,避免大模块仿真时间过长,
--timescale us
指定瞬态分析参数的时间单位为$\mu s$(如无指定默认为$ns$),
--tbStep 0.01
指定瞬态分析最大步长为$0.01\mu s$(如无指定默认为$0.01ns$),
--tbPulse 5
指定瞬态分析激励源最小脉宽为$5\mu s$(如无指定默认为$10ns$),
--capacitorLoad 1pF
指定输出负载电容为$1pF$(如无指定默认为$0.01pF$),
--WP 2u
指定全局PMOS单位宽度为$2\mu m$(如无指定默认为$3.5\mu m$),
--clearCache
清理${inputPath}/output/tmp文件夹,
-v
详细展开综合过程,
程序会在输入目录下的output
文件夹中生成带有激励源的网表文件,激励源会对所有的输入情况进行激励。上述脚本会输出./examples/output/top.sp
:
.LIB sm046005-1j.hspice typical
.OPTION POST
.PARAM WN=1u LP=0.35u LN=0.35u WP=2u
.GLOBAL VDD GND
VDD VDD GND 3.3
.SUBCKT INV nc in out
.LIB sm046005-1j.hspice typical
Mp out in VDD VDD PMOS_3P3 L=LP W=WP
Mn out in GND GND NMOS_3P3 L=LN W=WN
.ENDS INV
.SUBCKT OR in1 in2 out
.LIB sm046005-1j.hspice typical
Mp1 buf in1 VDD VDD PMOS_3P3 L=LP W=2*WP
Mp2 out_buf in2 buf buf PMOS_3P3 L=LP W=2*WP
Mn1 out_buf in1 GND GND NMOS_3P3 L=LN W=WN
Mn2 out_buf in2 GND GND NMOS_3P3 L=LN W=WN
XINV GND out_buf out INV
.ENDS OR
.SUBCKT XOR in1 in2 out
.LIB sm046005-1j.hspice typical
XINV_1 GND in1 in1_n INV
XINV_2 GND in2 in2_n INV
Mp1 buf1 in1 VDD VDD PMOS_3P3 L=LP W=2*WP
Mp2 out in2_n buf1 buf1 PMOS_3P3 L=LP W=2*WP
Mp3 buf2 in1_n VDD VDD PMOS_3P3 L=LP W=2*WP
Mp4 out in2 buf2 buf2 PMOS_3P3 L=LP W=2*WP
Mn1 out in1 buf3 buf3 NMOS_3P3 L=LN W=2*WN
Mn2 out in2_n buf3 buf3 NMOS_3P3 L=LN W=2*WN
Mn3 buf3 in1_n GND GND NMOS_3P3 L=LN W=2*WN
Mn4 buf3 in2 GND GND NMOS_3P3 L=LN W=2*WN
.ENDS XOR
.SUBCKT AND in1 in2 out
.LIB sm046005-1j.hspice typical
Mp1 out_buf in1 VDD VDD PMOS_3P3 L=LP W=WP
Mp2 out_buf in2 VDD VDD PMOS_3P3 L=LP W=WP
Mn1 out_buf in1 buf buf NMOS_3P3 L=LN W=2*WN
Mn2 buf in2 GND GND NMOS_3P3 L=LN W=2*WN
XINV GND out_buf out INV
.ENDS AND
.SUBCKT top_module a_0 b_0 a_1 b_1 a_2 b_2 a_3 b_3 cin sum_0 sum_1 sum_2 sum_3 cout
.LIB sm046005-1j.hspice typical
Rshort_cout cout carry_out_3 0
Rshort_carry_in_0 carry_in_0 cin 0
Rshort_carry_in_1 carry_in_1 carry_out_0 0
Rshort_carry_in_2 carry_in_2 carry_out_1 0
Rshort_carry_in_3 carry_in_3 carry_out_2 0
Xadd_01000 a_0 b_0 carry_in_0 sum_0 carry_out_0 add1
Xadd_11001 a_1 b_1 carry_in_1 sum_1 carry_out_1 add1
Xadd_21002 a_2 b_2 carry_in_2 sum_2 carry_out_2 add1
Xadd_31003 a_3 b_3 carry_in_3 sum_3 carry_out_3 add1
.ENDS top_module
.SUBCKT hadd a b s c
.LIB sm046005-1j.hspice typical
Mp1 buf1 a VDD VDD PMOS_3P3 L=LP W=2*WP
Mp2 out_buf b buf1 buf1 PMOS_3P3 L=LP W=2*WP
Mn1 out_buf a GND GND NMOS_3P3 L=LN W=WN
Mn2 out_buf b GND GND NMOS_3P3 L=LN W=WN
XAND a b c AND
Mp3 buf out_buf VDD VDD PMOS_3P3 L=LP W=2*WP
Mp4 s c buf buf PMOS_3P3 L=LP W=2*WP
Mn3 s out_buf GND GND NMOS_3P3 L=LN W=WN
Mn4 s c GND GND NMOS_3P3 L=LN W=WN
.ENDS hadd
.SUBCKT add1 a b cin sum cout
.LIB sm046005-1j.hspice typical
XOR1004 c1 c2 cout OR
Xhadd11005 a b s c1 hadd
Xhadd21006 s cin sum c2 hadd
.ENDS add1
X_TOP a_0 b_0 a_1 b_1 a_2 b_2 a_3 b_3 cin sum_0 sum_1 sum_2 sum_3 cout top_module
C_sum_0 sum_0 GND 1pF
C_sum_1 sum_1 GND 1pF
C_sum_2 sum_2 GND 1pF
C_sum_3 sum_3 GND 1pF
C_cout cout GND 1pF
V_a_0 a_0 GND PULSE(0V 3.3V 5us 0us 0us 5us 10us)
V_b_0 b_0 GND PULSE(0V 3.3V 10us 0us 0us 10us 20us)
V_a_1 a_1 GND PULSE(0V 3.3V 20us 0us 0us 20us 40us)
V_b_1 b_1 GND PULSE(0V 3.3V 40us 0us 0us 40us 80us)
V_a_2 a_2 GND PULSE(0V 3.3V 80us 0us 0us 80us 160us)
V_b_2 b_2 GND PULSE(0V 3.3V 160us 0us 0us 160us 320us)
V_a_3 a_3 GND PULSE(0V 3.3V 320us 0us 0us 320us 640us)
V_b_3 b_3 GND PULSE(0V 3.3V 640us 0us 0us 640us 1280us)
V_cin cin GND PULSE(0V 3.3V 1280us 0us 0us 1280us 2560us)
.TRAN 0.01us 2560us
.END
程序也会在output/testbench目录下生成RTL仿真激励文件testbench.v
:
`timescale 1ns/1ps
`include "top.v"
module test_top();
reg [ 3 : 0 ] a;
reg [ 3 : 0 ] b;
reg cin;
wire [ 3 : 0 ] sum;
wire cout;
top_module top_inst(
.a ( a),
.b ( b),
.cin ( cin),
.sum ( sum),
.cout ( cout)
);
integer a_tbInst_iter, b_tbInst_iter, cin_tbInst_iter;
initial begin
cin = 1'b0;
for(cin_tbInst_iter = 0; cin_tbInst_iter < 2; cin_tbInst_iter = cin_tbInst_iter + 1) begin
b = 4'b0;
for(b_tbInst_iter = 0; b_tbInst_iter < 16; b_tbInst_iter = b_tbInst_iter + 1) begin
a = 4'b0;
for(a_tbInst_iter = 0; a_tbInst_iter < 16; a_tbInst_iter = a_tbInst_iter + 1) begin
#5;
a = a + 1;
end
b = b + 1;
end
cin = cin + 1;
end
end
endmodule
同时也会在上述目录下生成ModelSim仿真脚本autorun.tcl
:
quit -sim
vlib work
vlog adders.v top.v testbench.v
vsim work.test_top -voptargs="+acc"
view wave
delete wave *
add wave sim:/test_top/*
radix -hex
run -all
如果环境变量中有ModelSim,会自动运行仿真脚本,并打开波形图
Linux自带,Windows可以安装Strawberry Perl
Linux自带,Windows可以安装Strawberry Perl里面自带
apt包管理器系统运行
$ sudo apt install liblog-dispatch-perl
Windows在命令行内运行
> cpan Log::Dispatch
建议在WSL Linux下开发,Perl的Language Server目前只能在Linux下运行,HSpice大家基本都装在Windows里面(如果装在Linux内当我没说),WSL可以允许Linux系统操作Windows系统内的文件,比VMWare的挂载共享文件夹方便多了。
用于跨平台开发与调试
用于跨平台开发与调试
必要的编译工具和下载工具,apt包管理器系统运行
$ sudo apt install wget ca-certificates build-essential
用于VSCode调试,apt包管理器系统运行
$ sudo apt install libanyevent-perl libio-aio-perl && sudo cpan Perl::LanguageServer
用于数据结构可视化,apt包管理器系统运行
$ sudo install graphviz perl-tk
目前仅仅支持RTL级建模,不支持行为级建模。
支持的语句和运算符包括:
允许对线网与线网总线赋值,允许~&|^
运算符,暂不支持规约运算,暂不支持{}
线网连接,暂不支持?:
三元运算符。
允许定义模块,定义模块的时候需要声明输入与输出线网与线网总线类型input|output
,暂不支持inout
类型和模块内部声明类型。
允许定义线网和线网总线。
允许使用//进行注释。
允许例化模块,允许例化模块Array,暂不支持generate。 例化模块需要使用端口名称进行例化,暂不支持根据声明位置进行例化。 例化连接的端口必须为线网名称与索引,暂不支持表达式。
^&|
的规约运算
?:
三元运算符
{}
连接运算
按照位置例化,端口为表达式
组合逻辑自动综合为静态互补逻辑,而非逻辑门级联