Add Yosys and update flow_flow Perl Script

This commit is contained in:
tangxifan 2018-11-30 21:14:43 -07:00
parent e223868df8
commit 4f5f8de46f
792 changed files with 141456 additions and 130 deletions

View File

@ -1,26 +1,27 @@
# Standard Configuration Example
[dir_path]
script_base = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/scripts/
benchmark_dir = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/benchmarks/FPGA_SPICE_bench
odin2_path = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/not_used_atm/odin2.exe
cirkit_path = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/not_used_atm/cirkit
abc_path = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/../abc/abc
abc_mccl_path = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/../abc_with_bb_support/abc
abc_with_bb_support_path = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/../abc_with_bb_support/abc
mpack1_path = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/not_used_atm/mpack1
m2net_path = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/not_used_atm/m2net
mpack2_path = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/not_used_atm/mpack2
vpr_path = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/../vpr7_x2p/vpr/vpr
rpt_dir = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/results
ace_path = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/../ace2/ace
script_base = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/scripts/
benchmark_dir = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/benchmarks/RelChip_verilog_bench/
yosys_path = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/../yosys/yosys
odin2_path = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/not_used_atm/odin2.exe
cirkit_path = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/not_used_atm/cirkit
abc_path = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/../abc/abc
abc_mccl_path = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/../abc_with_bb_support/abc
abc_with_bb_support_path = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/../abc_with_bb_support/abc
mpack1_path = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/not_used_atm/mpack1
m2net_path = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/not_used_atm/m2net
mpack2_path = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/not_used_atm/mpack2
vpr_path = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/../vpr7_x2p/vpr/vpr
rpt_dir = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/results
ace_path = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/../ace2/ace
[flow_conf]
flow_type = standard #standard|mpack2|mpack1|vtr_standard|vtr
vpr_arch = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/arch/fpga_spice/k6_N10_sram_tsmc40nm_TT.xml # Use relative path under VPR folder is OK
flow_type = yosys_vpr #standard|mpack2|mpack1|vtr_standard|vtr|yosys_vpr
vpr_arch = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/arch/fpga_spice/k6_N10_sram_tsmc40nm_TT.xml # Use relative path under VPR folder is OK
mpack1_abc_stdlib = DRLC7T_SiNWFET.genlib # Use relative path under ABC folder is OK
m2net_conf = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/m2net_conf/m2x2_SiNWFET.conf
m2net_conf = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/m2net_conf/m2x2_SiNWFET.conf
mpack2_arch = K6_pattern7_I24.arch
power_tech_xml = /research/ece/lnis/USERS/chauviere/OpenFPGA/fpga_flow/tech/PTM_45nm/45nm.xml # Use relative path under VPR folder is OK
power_tech_xml = /research/ece/lnis/USERS/tang/research/EDA/OpenFPGA/fpga_flow/tech/PTM_45nm/45nm.xml # Use relative path under VPR folder is OK
[csv_tags]
mpack1_tags = Global mapping efficiency:|efficiency:|occupancy wo buf:|efficiency wo buf:

View File

@ -1,4 +1,15 @@
# Make sure a clear start
set output_conf = ${PWD}/configs/fpga_spice/k6_N10_sram_tsmc40nm_TT.conf
set benchmark_list = ${PWD}/benchmarks/fpga_spice_bench.txt
set benchmark_path = ${PWD}/benchmarks/FPGA_SPICE_bench/
set arch_file = ${PWD}/arch/fpga_spice/k6_N10_sram_tsmc40nm_TT.xml
set flow_type = standard
set power_property_xml = ${PWD}/tech/PTM_45nm/45nm.xml
set csv_prefix = k6_N10_sram_tsmc40nm
set fpga_spice_flow_config_file = ${PWD}/vpr_fpga_spice_conf/sample.conf
set vpr_flow_report_dir = ${PWD}/csv_rpts/fpga_spice/
set fpga_spice_flow_report_dir = ${PWD}/vpr_fpga_spice_csv_rpts/
set fpga_spice_task_list_dir = ${PWD}/vpr_fpga_spice_task_lists/
# Sweep Corner Cases
set corner_list = (TT)
@ -12,10 +23,10 @@ foreach j ($corner_list)
set mc_opt = ()
endif
perl scripts/generate_config.pl
perl scripts/generate_config.pl -output_conf $output_conf -arch $arch_file -benchmark_path $benchmark_path -flow_type $flow_type -power_property_xml $power_property_xml
perl scripts/fpga_flow.pl -conf ./configs/fpga_spice/k6_N10_sram_tsmc40nm_$j\.conf -benchmark ./benchmarks/fpga_spice_bench.txt -rpt ./csv_rpts/fpga_spice/k6_N10_sram_tsmc40nm_bench_$j\.csv -N 10 -K 6 -power -remove_designs -multi_thread 1 -vpr_fpga_spice ./vpr_fpga_spice_task_lists/k6_N10_sram_tsmc40nm -vpr_fpga_spice_rename_illegal_port -vpr_fpga_spice_sim_mt_num 16 -vpr_fpga_spice_print_top_tb -vpr_fpga_spice_print_component_tb -vpr_fpga_spice_print_grid_tb #-vpr_fpga_spice_parasitic_net_estimation_off #-vpr_fpga_spice_leakage_only
perl scripts/fpga_flow.pl -conf $output_conf -benchmark $benchmark_list -rpt ${vpr_flow_report_dir}${csv_prefix}_$j\.csv -N 10 -K 6 -power -remove_designs -multi_thread 1 -vpr_fpga_spice ${fpga_spice_task_list_dir}${csv_prefix} -vpr_fpga_spice_rename_illegal_port -vpr_fpga_spice_sim_mt_num 16 -vpr_fpga_spice_print_top_tb -vpr_fpga_spice_print_component_tb -vpr_fpga_spice_print_grid_tb
perl scripts/run_fpga_spice.pl -conf ./vpr_fpga_spice_conf/sample.conf -task ./vpr_fpga_spice_task_lists/k6_N10_sram_tsmc40nm_standard.txt -rpt ./vpr_fpga_spice_csv_rpts/k6_N10_sram_tsmc40_spice_bench_$j\.csv $mc_opt -parse_top_tb -multi_thread 2 -parse_pb_mux_tb -parse_cb_mux_tb -parse_sb_mux_tb -parse_lut_tb -parse_hardlogic_tb -parse_grid_tb -parse_cb_tb -parse_sb_tb
perl scripts/run_fpga_spice.pl -conf ${fpga_spice_flow_config_file} -task ${fpga_spice_task_list_dir}${csv_prefix}_${flow_type}.txt -rpt ${fpga_spice_flow_report_dir}${csv_prefix}_$j\.csv $mc_opt -parse_top_tb -multi_thread 2 -parse_pb_mux_tb -parse_cb_mux_tb -parse_sb_mux_tb -parse_lut_tb -parse_hardlogic_tb -parse_grid_tb -parse_cb_tb -parse_sb_tb
end

View File

@ -43,7 +43,8 @@ my @supported_flows = ("standard",
"mpack2",
"mpack1",
"vtr",
"vtr_standard");
"vtr_standard",
"yosys_vpr");
my %selected_flows;
# Configuration file keywords list
@ -60,6 +61,7 @@ my @sctgy;
# refer to the keywords of dir_path
@{$sctgy[0]} = ("script_base",
"benchmark_dir",
"yosys_path",
"odin2_path",
"cirkit_path",
"abc_mccl_path",
@ -170,21 +172,15 @@ sub print_usage()
return 1;
}
sub spot_option($ $)
{
sub spot_option($ $) {
my ($start,$target) = @_;
my ($arg_no,$flag) = (-1,"unfound");
for (my $iarg = $start; $iarg < $#ARGV+1; $iarg++)
{
if ($ARGV[$iarg] eq $target)
{
if ("found" eq $flag)
{
for (my $iarg = $start; $iarg < $#ARGV+1; $iarg++) {
if ($ARGV[$iarg] eq $target) {
if ("found" eq $flag) {
print "Error: Repeated Arguments!(IndexA: $arg_no,IndexB: $iarg)\n";
&print_usage();
}
else
{
} else {
$flag = "found";
$arg_no = $iarg;
}
@ -199,49 +195,35 @@ sub spot_option($ $)
# 1. Option Name
# 2. Whether Option with value. if yes, choose "on"
# 3. Whether Option is mandatory. If yes, choose "on"
sub read_opt_into_hash($ $ $)
{
sub read_opt_into_hash($ $ $) {
my ($opt_name,$opt_with_val,$mandatory) = @_;
# Check the -$opt_name
my ($opt_fact) = ("-".$opt_name);
my ($cur_arg) = (0);
my ($argfd) = (&spot_option($cur_arg,"$opt_fact"));
if ($opt_with_val eq "on")
{
if (-1 != $argfd)
{
if ($ARGV[$argfd+1] =~ m/^-/)
{
if ($opt_with_val eq "on") {
if (-1 != $argfd) {
if ($ARGV[$argfd+1] =~ m/^-/) {
print "The next argument cannot start with '-'!\n";
print "it implies an option!\n";
}
else
{
} else {
$opt_ptr->{"$opt_name\_val"} = $ARGV[$argfd+1];
$opt_ptr->{"$opt_name"} = "on";
}
}
else
{
} else {
$opt_ptr->{"$opt_name"} = "off";
if ($mandatory eq "on")
{
if ($mandatory eq "on") {
print "Mandatory option: $opt_fact is missing!\n";
&print_usage();
}
}
}
else
{
if (-1 != $argfd)
{
} else {
if (-1 != $argfd) {
$opt_ptr->{"$opt_name"} = "on";
}
else
{
else {
$opt_ptr->{"$opt_name"} = "off";
if ($mandatory eq "on")
{
if ($mandatory eq "on") {
print "Mandatory option: $opt_fact is missing!\n";
&print_usage();
}
@ -251,11 +233,9 @@ sub read_opt_into_hash($ $ $)
}
# Read options
sub opts_read()
{
sub opts_read() {
# if no arguments detected, print the usage.
if (-1 == $#ARGV)
{
if (-1 == $#ARGV) {
print "Error : No input arguments!\n";
print "Help desk:\n";
&print_usage();
@ -269,19 +249,16 @@ sub opts_read()
my $argfd;
# Check help fist
$argfd = &spot_option($cur_arg,"-help");
if (-1 != $argfd)
{
if (-1 != $argfd) {
print "Help desk:\n";
&print_usage();
}
# Then Check the debug with highest priority
$argfd = &spot_option($cur_arg,"-debug");
if (-1 != $argfd)
{
if (-1 != $argfd) {
$opt_ptr->{"debug"} = "on";
}
else
{
else {
$opt_ptr->{"debug"} = "off";
}
# Check mandatory options
@ -338,12 +315,12 @@ sub opts_read()
}
# List the options
sub print_opts()
{
sub print_opts() {
print "List your options\n";
while(my ($key,$value) = each(%opt_h))
{print "$key : $value\n";}
while(my ($key,$value) = each(%opt_h)) {
print "$key : $value\n";
}
return 1;
}
@ -553,6 +530,70 @@ sub run_abc_libmap($ $ $)
chdir $cwd;
}
# Run yosys synthesis with ABC LUT mapping
sub run_yosys_fpgamap($ $ $ $) {
my ($bm, $bm_path, $blif_out, $log) = @_;
my ($cmd_log) = ($log);
$cmd_log =~ s/log$/ys/;
# Get Yosys path
my ($yosys_dir,$yosys_name) = &split_prog_path($conf_ptr->{dir_path}->{yosys_path}->{val});
print "Entering $yosys_dir\n";
chdir $yosys_dir;
my ($lut_num) = $opt_ptr->{K_val};
# Create yosys synthesize script
my ($YOSYS_CMD_FH) = (FileHandle->new);
if ($YOSYS_CMD_FH->open("> $cmd_log")) {
print "INFO: auto generating cmds for Yosys ($cmd_log) ...\n";
} else {
die "ERROR: fail to auto generating cmds for Yosys ($cmd_log) ...\n";
}
# Output the standard format (refer to VTR_flow script)
print $YOSYS_CMD_FH "# Yosys synthesis script for $bm\n";
print $YOSYS_CMD_FH "# read Verilog \n";
print $YOSYS_CMD_FH "read_verilog -nolatches $bm_path\n";
print $YOSYS_CMD_FH "\n";
print $YOSYS_CMD_FH "# Technology mapping\n";
print $YOSYS_CMD_FH "hierarchy -top $bm\n";
print $YOSYS_CMD_FH "proc\n";
print $YOSYS_CMD_FH "techmap -D NO_LUT -map +/adff2dff.v\n";
print $YOSYS_CMD_FH "\n";
print $YOSYS_CMD_FH "# Synthesis\n";
print $YOSYS_CMD_FH "synth -top $bm -flatten\n";
print $YOSYS_CMD_FH "clean\n";
print $YOSYS_CMD_FH "\n";
print $YOSYS_CMD_FH "# LUT mapping \n";
print $YOSYS_CMD_FH "abc -lut $lut_num\n";
print $YOSYS_CMD_FH "\n";
print $YOSYS_CMD_FH "# Check \n";
print $YOSYS_CMD_FH "synth -run check\n";
print $YOSYS_CMD_FH "\n";
print $YOSYS_CMD_FH "# C;ean and output blif \n";
print $YOSYS_CMD_FH "opt_clean -purge\n";
print $YOSYS_CMD_FH "write_blif $blif_out\n";
close($YOSYS_CMD_FH);
#
# Create a local copy for the commands
system("/bin/tcsh -cx './$yosys_name $cmd_log > $log'");
if (!(-e $blif_out)) {
die "ERROR: Fail Yosys for benchmark $bm.\n";
}
print "Leaving $yosys_dir\n";
chdir $cwd;
}
# Run ABC by FPGA-oriented synthesis
sub run_abc_fpgamap($ $ $)
{
@ -885,6 +926,7 @@ sub extract_vpr_power_esti($ $ $ $)
if ($line =~ m/$tmp\s*([0-9E\-+.]+)/i) {
$rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{power}->{$tmpkw} = $1;
my @tempdata = split /\./,$rpt_ptr->{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{power}->{$tmpkw};
#print "$tmpkw\n";
$rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{power}->{$tmpkw} = join('.',$tempdata[0],$tempdata[1]);
$rpt_h{$tag}->{$bm}->{$opt_ptr->{N_val}}->{$type}->{power}->{$tmpkw} =~ s/0$//;
}
@ -1378,6 +1420,8 @@ sub init_fpga_spice_task($) {
&generate_path($task_dir_path);
print "INFO: writting FPGA SPICE task list $task_file\n";
# Open the task file handler
my ($TASKFH) = (FileHandle->new);
if ($TASKFH->open("> $task_file")) {
@ -1392,6 +1436,7 @@ sub init_fpga_spice_task($) {
# Close the file handler
close($TASKFH);
}
# Print a line into task file which contains task info of FPGA SPICE.
@ -1564,6 +1609,113 @@ sub run_mig_mccl_flow($ $ $ $) {
return;
}
# Run Yosys-VPR flow
sub run_yosys_vpr_flow($ $ $ $ $)
{
my ($tag,$benchmark_file,$vpr_arch,$flow_enhance, $parse_results) = @_;
my ($benchmark, $rpt_dir, $prefix);
my ($yosys_bm,$yosys_blif_out,$yosys_log,$yosys_blif_out_bak);
my @tokens = split('/', $benchmark_file);
$benchmark = $tokens[0];
# Prepare for the output folder
$rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag";
&generate_path($rpt_dir);
# Run Yosys flow
$yosys_bm = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark_file";
$prefix = "$rpt_dir/$benchmark\_"."K$opt_ptr->{K_val}\_"."N$opt_ptr->{N_val}\_";
$yosys_blif_out = "$prefix"."yosys.blif";
$yosys_log = "$prefix"."yosys.log";
&run_yosys_fpgamap($benchmark, $yosys_bm, $yosys_blif_out, $yosys_log);
# Files for ace
my ($act_file,$ace_new_blif,$ace_log) = ("$prefix"."ace.act","$prefix"."ace.blif","$prefix"."ace.log");
&run_ace_in_flow($prefix, $yosys_blif_out, $act_file, $ace_new_blif, $ace_log);
# Files for VPR
my ($vpr_net,$vpr_place,$vpr_route,$vpr_reroute_log,$vpr_log);
$vpr_net = "$prefix"."vpr.net";
$vpr_place = "$prefix"."vpr.place";
$vpr_route = "$prefix"."vpr.route";
$vpr_log = "$prefix"."vpr.log";
$vpr_reroute_log = "$prefix"."vpr_reroute.log";
&run_vpr_in_flow($tag, $benchmark, $benchmark_file, $yosys_blif_out, $vpr_arch, $act_file, $vpr_net, $vpr_place, $vpr_route, $vpr_log, $vpr_reroute_log, $parse_results);
return;
}
# Parse Yosys-VPR flow
sub parse_yosys_vpr_flow_results($ $ $ $)
{
my ($tag,$benchmark_file,$vpr_arch,$flow_enhance) = @_;
my ($benchmark, $rpt_dir, $prefix);
my ($yosys_bm,$yosys_blif_out,$yosys_log,$yosys_blif_out_bak);
my @tokens = split('/', $benchmark_file);
$benchmark = $tokens[0];
# Prepare for the output folder
$rpt_dir = "$conf_ptr->{dir_path}->{rpt_dir}->{val}"."/$benchmark/$tag";
&generate_path($rpt_dir);
# Run Yosys flow
$yosys_bm = "$conf_ptr->{dir_path}->{benchmark_dir}->{val}"."/$benchmark_file";
$prefix = "$rpt_dir/$benchmark\_"."K$opt_ptr->{K_val}\_"."N$opt_ptr->{N_val}\_";
$yosys_blif_out = "$prefix"."yosys.blif";
$yosys_log = "$prefix"."yosys.log";
# Files for ace
my ($act_file,$ace_new_blif,$ace_log) = ("$prefix"."ace.act","$prefix"."ace.blif","$prefix"."ace.log");
# Files for VPR
my ($vpr_net,$vpr_place,$vpr_route,$vpr_reroute_log,$vpr_log);
$vpr_net = "$prefix"."vpr.net";
$vpr_place = "$prefix"."vpr.place";
$vpr_route = "$prefix"."vpr.route";
$vpr_log = "$prefix"."vpr.log";
$vpr_reroute_log = "$prefix"."vpr_reroute.log";
if ("on" eq $opt_ptr->{min_route_chan_width}) {
&extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log.".min_chan_width",$opt_ptr->{K_val},"on",1);
&extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val},"off",1);
&extract_vpr_stats($tag,$benchmark,$vpr_log.".min_chan_width",$opt_ptr->{K_val});
&extract_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val});
} elsif ("on" eq $opt_ptr->{fix_route_chan_width}) {
&extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val},"off",1);
&extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val});
if (-e $vpr_reroute_log) {
&extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val},"off",1);
&extract_vpr_stats($tag,$benchmark,$vpr_reroute_log,$opt_ptr->{K_val});
}
} else {
&extract_min_chan_width_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val},"on",1);
&extract_vpr_stats($tag,$benchmark,$vpr_log,$opt_ptr->{K_val});
}
# Extract data from VPR Power stats
if ("on" eq $opt_ptr->{power}) {
&extract_vpr_power_esti($tag,$yosys_blif_out,$benchmark,$opt_ptr->{K_val});
}
# TODO: HOW TO DEAL WITH SPICE NETLISTS???
# Output a file contain information of SPICE Netlists
if ("on" eq $opt_ptr->{vpr_fpga_spice}) {
&output_fpga_spice_task("$opt_ptr->{vpr_fpga_spice_val}"."_$tag.txt", $benchmark, $yosys_blif_out, $rpt_dir);
}
return;
}
sub run_standard_flow($ $ $ $ $)
{
@ -1571,7 +1723,6 @@ sub run_standard_flow($ $ $ $ $)
my ($benchmark, $rpt_dir,$prefix);
my ($abc_bm,$abc_blif_out,$abc_log,$abc_blif_out_bak);
my ($mpack_blif_out,$mpack_stats,$mpack_log);
my ($vpr_net,$vpr_place,$vpr_route,$vpr_reroute_log,$vpr_log);
$benchmark = $benchmark_file;
$benchmark =~ s/\.blif$//g;
@ -2288,6 +2439,8 @@ sub run_benchmark_selected_flow($ $ $)
&run_mccl_flow("mccl",$benchmark,$conf_ptr->{flow_conf}->{vpr_arch}->{val}, $parse_results);
} elsif ($flow_type eq "mig_mccl") {
&run_mig_mccl_flow("mig_mccl",$benchmark,$conf_ptr->{flow_conf}->{vpr_arch}->{val}, $parse_results);
} elsif ($flow_type eq "yosys_vpr") {
&run_yosys_vpr_flow("yosys_vpr",$benchmark,$conf_ptr->{flow_conf}->{vpr_arch}->{val}, "classic", $parse_results);
} else {
die "ERROR: unsupported flow type ($flow_type) is chosen!\n";
}
@ -2314,6 +2467,8 @@ sub parse_benchmark_selected_flow($ $) {
&parse_standard_flow_results("mccl", $benchmark, $conf_ptr->{flow_conf}->{vpr_arch}->{val}, "abc_black_box");
} elsif ($flow_type eq "mig_mccl") {
&parse_standard_flow_results("mig_mccl", $benchmark, $conf_ptr->{flow_conf}->{vpr_arch}->{val}, "abc_black_box");
} elsif ($flow_type eq "yosys_vpr") {
&parse_yosys_vpr_flow_results("yosys_vpr",$benchmark,$conf_ptr->{flow_conf}->{vpr_arch}->{val},"abc_black_box");
} else {
die "ERROR: unsupported flow type ($flow_type) is chosen!\n";
}
@ -2626,6 +2781,74 @@ sub gen_csv_rpt_vtr_flow($ $)
}
}
sub gen_csv_rpt_yosys_vpr_flow($ $)
{
my ($tag,$CSVFH) = @_;
my ($tmp,$ikw,$tmpkw);
my @keywords;
my ($K_val,$N_val) = ($opt_ptr->{K_val},$opt_ptr->{N_val});
# Print out Standard Stats First
print $CSVFH "$tag";
print $CSVFH ",LUTs";
if ("on" eq $opt_ptr->{min_route_chan_width}) {
print $CSVFH ",min_route_chan_width";
print $CSVFH ",fix_route_chan_width";
} elsif ("on" eq $opt_ptr->{fix_route_chan_width}) {
print $CSVFH ",fix_route_chan_width";
} else {
print $CSVFH ",min_route_chan_width";
}
@keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val};
#foreach $tmpkw(@keywords) {
for($ikw=0; $ikw < ($#keywords+1); $ikw++) {
print $CSVFH ",$keywords[$ikw]";
}
if ("on" eq $opt_ptr->{power}) {
@keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_power_tags}->{val};
#foreach $tmpkw(@keywords) {
for($ikw=0; $ikw < ($#keywords+1); $ikw++) {
print $CSVFH ",$keywords[$ikw]";
}
print $CSVFH ",Total Power,Total Dynamic Power,Total Leakage Power";
}
print $CSVFH "\n";
# Check log/stats one by one
foreach $tmp(@benchmark_names) {
my @tokens = split('/', $tmp);
$tmp = $tokens[0];
print $CSVFH "$tmp";
print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{LUTs}";
if ("on" eq $opt_ptr->{min_route_chan_width}) {
print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{min_route_chan_width}";
print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{fix_route_chan_width}";
} elsif ("on" eq $opt_ptr->{fix_route_chan_width}) {
print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{fix_route_chan_width}";
} else {
print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{min_route_chan_width}";
}
#foreach $tmpkw(@keywords) {
@keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val};
for($ikw=0; $ikw < ($#keywords+1); $ikw++) {
$tmpkw = $keywords[$ikw];
$tmpkw =~ s/\s//g;
print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{$keywords[$ikw]}";
}
if ("on" eq $opt_ptr->{power}) {
@keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_power_tags}->{val};
for($ikw=0; $ikw < ($#keywords+1); $ikw++) {
$tmpkw = $keywords[$ikw];
$tmpkw =~ s/\s//g;
print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{$keywords[$ikw]}";
}
print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{total}";
print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{dynamic}";
print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{power}->{leakage}";
}
print $CSVFH "\n";
}
}
sub gen_csv_rpt_standard_flow($ $)
{
my ($tag,$CSVFH) = @_;
@ -2928,6 +3151,11 @@ sub gen_csv_rpt($)
print "INFO: writing mig_mccl flow results ...\n";
&gen_csv_rpt_standard_flow("mig_mccl",$CSVFH);
}
} elsif ($flow_type eq "yosys_vpr") {
if (1 == &check_flow_all_benchmarks_done("yosys_vpr")) {
print "INFO: writing yosys_vpr flow results ...\n";
&gen_csv_rpt_yosys_vpr_flow("yosys_vpr",$CSVFH);
}
} else {
die "ERROR: flow_type: $flow_type is not supported!\n";
}

View File

@ -10,26 +10,150 @@ my $mydate = gmctime();
use File::Path;
use Cwd;
use FileHandle;
# Global Variants
# input Option Hash
my %opt_h;
my $opt_ptr = \%opt_h;
my $CONF_HANDLE;
my ($SCRIPTS_PATH, $CONFIG_PATH, $FPGA_FLOW_PATH);
my ($SCRIPTS_PATH, $CONFIG_FILEPATH, $FPGA_FLOW_PATH);
# !!! this script is called in the parent folder: fpga_flow. If you use the script in the scripts folder it is not going to work! !!!
$FPGA_FLOW_PATH = getcwd();
$SCRIPTS_PATH = "${FPGA_FLOW_PATH}/scripts";
$CONFIG_PATH = "${FPGA_FLOW_PATH}/configs/fpga_spice/k6_N10_sram_tsmc40nm_TT.conf";
$CONFIG_FILEPATH = "${FPGA_FLOW_PATH}/configs/fpga_spice/k6_N10_sram_tsmc40nm_TT.conf";
sub print_usage()
{
print "\nThe configuration file is being generated. \nThe output is placed in ../configs/fpga_spice/k6_N10_sram_tsmc40nm_TT.conf\n";
return 1;
sub spot_option($ $) {
my ($start,$target) = @_;
my ($arg_no,$flag) = (-1,"unfound");
for (my $iarg = $start; $iarg < $#ARGV+1; $iarg++) {
if ($ARGV[$iarg] eq $target) {
if ("found" eq $flag) {
print "Error: Repeated Arguments!(IndexA: $arg_no,IndexB: $iarg)\n";
&print_usage();
} else {
$flag = "found";
$arg_no = $iarg;
}
}
}
# return the arg_no if target is found
# or return -1 when target is missing
return $arg_no;
}
# Specify in the input list,
# 1. Option Name
# 2. Whether Option with value. if yes, choose "on"
# 3. Whether Option is mandatory. If yes, choose "on"
sub read_opt_into_hash($ $ $) {
my ($opt_name,$opt_with_val,$mandatory) = @_;
# Check the -$opt_name
my ($opt_fact) = ("-".$opt_name);
my ($cur_arg) = (0);
my ($argfd) = (&spot_option($cur_arg,"$opt_fact"));
if ($opt_with_val eq "on") {
if (-1 != $argfd) {
if ($ARGV[$argfd+1] =~ m/^-/) {
print "The next argument cannot start with '-'!\n";
print "it implies an option!\n";
} else {
$opt_ptr->{"$opt_name\_val"} = $ARGV[$argfd+1];
$opt_ptr->{"$opt_name"} = "on";
}
} else {
$opt_ptr->{"$opt_name"} = "off";
if ($mandatory eq "on") {
print "Mandatory option: $opt_fact is missing!\n";
&print_usage();
}
}
} else {
if (-1 != $argfd) {
$opt_ptr->{"$opt_name"} = "on";
}
else {
$opt_ptr->{"$opt_name"} = "off";
if ($mandatory eq "on") {
print "Mandatory option: $opt_fact is missing!\n";
&print_usage();
}
}
}
return 1;
}
# Read options
sub opts_read() {
# if no arguments detected, print the usage.
if (-1 == $#ARGV) {
print "Error : No input arguments!\n";
print "Help desk:\n";
&print_usage();
exit(1);
}
# Read in the options
my ($cur_arg,$arg_found);
$cur_arg = 0;
print "Analyzing your options...\n";
# Read the options with internal options
my $argfd;
# Check help fist
$argfd = &spot_option($cur_arg,"-help");
if (-1 != $argfd) {
print "Help desk:\n";
&print_usage();
}
# Then Check the debug with highest priority
$argfd = &spot_option($cur_arg,"-debug");
if (-1 != $argfd) {
$opt_ptr->{"debug"} = "on";
}
else {
$opt_ptr->{"debug"} = "off";
}
# Check mandatory options
# Check the -conf
# Read Opt into Hash(opt_ptr) : "opt_name","with_val","mandatory"
&read_opt_into_hash("output_conf","on","on");
&read_opt_into_hash("arch","on","on");
&read_opt_into_hash("benchmark_path","on","on");
&read_opt_into_hash("flow_type","on","on");
&read_opt_into_hash("power_property_xml","on","on");
&print_opts();
return 1;
}
# List the options
sub print_opts() {
print "List your options\n";
while(my ($key,$value) = each(%opt_h)) {
print "$key : $value\n";
}
return 1;
}
sub print_usage() {
print "generate configuration file for FPGA flow.\n";
print "Usage: perl generate_config.pl <options>\n";
print " Mandatory options:\n";
print " -output_conf <string>: specify the path of configuration file to be outputted\n";
print " -arch <string>: specify the architecture file\n";
print " -benchmark_path <string>: specify the path of benchmark files\n";
print " -flow_type <string> : specify the type of FPGA flow to run\n";
print " -power_property_xml <string> : specify the XML file containing power property of FPGA architectures\n";
return 1;
}
# Create paths if it does not exist.
sub generate_path($)
{
sub generate_path($) {
my ($mypath) = @_;
if (!(-e "$mypath"))
{
if (!(-e "$mypath")) {
mkpath "$mypath";
print "Path($mypath) does not exist...Create it.\n";
}
@ -37,65 +161,87 @@ sub generate_path($)
}
# Opens the file in order to write into it
sub open_file($)
{
my ($mypath) = @_;
open ($CONF_HANDLE, "> $mypath") or die "Can't open $mypath: $!";
return 1;
sub open_file($) {
my ($mypath) = @_;
open ($CONF_HANDLE, "> $mypath") or die "Can't open $mypath: $!";
return 1;
}
# Generates the content of the configuration file
sub generate_file($)
{
my ($my_path) = @_;
print $CONF_HANDLE "# Standard Configuration Example\n";
print $CONF_HANDLE "[dir_path]\n";
print $CONF_HANDLE "script_base = $FPGA_FLOW_PATH/scripts/\n";
print $CONF_HANDLE "benchmark_dir = ${FPGA_FLOW_PATH}/benchmarks/FPGA_SPICE_bench\n";
print $CONF_HANDLE "odin2_path = ${FPGA_FLOW_PATH}/not_used_atm/odin2.exe\n";
print $CONF_HANDLE "cirkit_path = ${FPGA_FLOW_PATH}/not_used_atm/cirkit\n";
print $CONF_HANDLE "abc_path = ${FPGA_FLOW_PATH}/../abc/abc\n";
print $CONF_HANDLE "abc_mccl_path = ${FPGA_FLOW_PATH}/../abc_with_bb_support/abc\n";
print $CONF_HANDLE "abc_with_bb_support_path = ${FPGA_FLOW_PATH}/../abc_with_bb_support/abc\n";
print $CONF_HANDLE "mpack1_path = ${FPGA_FLOW_PATH}/not_used_atm/mpack1\n";
print $CONF_HANDLE "m2net_path = ${FPGA_FLOW_PATH}/not_used_atm/m2net\n";
print $CONF_HANDLE "mpack2_path = ${FPGA_FLOW_PATH}/not_used_atm/mpack2\n";
print $CONF_HANDLE "vpr_path = ${FPGA_FLOW_PATH}/../vpr7_x2p/vpr/vpr\n";
print $CONF_HANDLE "rpt_dir = ${FPGA_FLOW_PATH}/results\n";
print $CONF_HANDLE "ace_path = ${FPGA_FLOW_PATH}/../ace2/ace\n";
print $CONF_HANDLE "\n";
print $CONF_HANDLE "[flow_conf]\n";
print $CONF_HANDLE "flow_type = standard #standard|mpack2|mpack1|vtr_standard|vtr\n";
print $CONF_HANDLE "vpr_arch = ${FPGA_FLOW_PATH}/arch/fpga_spice/k6_N10_sram_tsmc40nm_TT.xml # Use relative path under VPR folder is OK\n";
print $CONF_HANDLE "mpack1_abc_stdlib = DRLC7T_SiNWFET.genlib # Use relative path under ABC folder is OK\n";
print $CONF_HANDLE "m2net_conf = ${FPGA_FLOW_PATH}/m2net_conf/m2x2_SiNWFET.conf\n";
print $CONF_HANDLE "mpack2_arch = K6_pattern7_I24.arch\n";
print $CONF_HANDLE "power_tech_xml = ${FPGA_FLOW_PATH}/tech/PTM_45nm/45nm.xml # Use relative path under VPR folder is OK\n";
print $CONF_HANDLE "\n";
print $CONF_HANDLE "[csv_tags]\n";
print $CONF_HANDLE "mpack1_tags = Global mapping efficiency:|efficiency:|occupancy wo buf:|efficiency wo buf:\n";
print $CONF_HANDLE "mpack2_tags = BLE Number:|BLE Fill Rate: \n";
print $CONF_HANDLE "vpr_tags = Netlist clb blocks:|Final critical path:|Total logic delay:|total net delay:|Total routing area:|Total used logic block area:|Total wirelength:|Packing took|Placement took|Routing took|Average net density:|Median net density:|Recommend no. of clock cycles:\n";
print $CONF_HANDLE "vpr_power_tags = PB Types|Routing|Switch Box|Connection Box|Primitives|Interc Structures|lut6|ff\n";
return 1;
my ($my_path) = @_;
print $CONF_HANDLE "# Standard Configuration Example\n";
print $CONF_HANDLE "[dir_path]\n";
print $CONF_HANDLE "script_base = $FPGA_FLOW_PATH/scripts/\n";
print $CONF_HANDLE "benchmark_dir = $opt_ptr->{benchmark_path_val}\n";
print $CONF_HANDLE "yosys_path = ${FPGA_FLOW_PATH}/../yosys/yosys\n";
print $CONF_HANDLE "odin2_path = ${FPGA_FLOW_PATH}/not_used_atm/odin2.exe\n";
print $CONF_HANDLE "cirkit_path = ${FPGA_FLOW_PATH}/not_used_atm/cirkit\n";
print $CONF_HANDLE "abc_path = ${FPGA_FLOW_PATH}/../abc/abc\n";
print $CONF_HANDLE "abc_mccl_path = ${FPGA_FLOW_PATH}/../abc_with_bb_support/abc\n";
print $CONF_HANDLE "abc_with_bb_support_path = ${FPGA_FLOW_PATH}/../abc_with_bb_support/abc\n";
print $CONF_HANDLE "mpack1_path = ${FPGA_FLOW_PATH}/not_used_atm/mpack1\n";
print $CONF_HANDLE "m2net_path = ${FPGA_FLOW_PATH}/not_used_atm/m2net\n";
print $CONF_HANDLE "mpack2_path = ${FPGA_FLOW_PATH}/not_used_atm/mpack2\n";
print $CONF_HANDLE "vpr_path = ${FPGA_FLOW_PATH}/../vpr7_x2p/vpr/vpr\n";
print $CONF_HANDLE "rpt_dir = ${FPGA_FLOW_PATH}/results\n";
print $CONF_HANDLE "ace_path = ${FPGA_FLOW_PATH}/../ace2/ace\n";
print $CONF_HANDLE "\n";
print $CONF_HANDLE "[flow_conf]\n";
print $CONF_HANDLE "flow_type = $opt_ptr->{flow_type_val} #standard|mpack2|mpack1|vtr_standard|vtr|yosys_vpr\n";
print $CONF_HANDLE "vpr_arch = $opt_ptr->{arch_val} # Use relative path under VPR folder is OK\n";
print $CONF_HANDLE "mpack1_abc_stdlib = DRLC7T_SiNWFET.genlib # Use relative path under ABC folder is OK\n";
print $CONF_HANDLE "m2net_conf = ${FPGA_FLOW_PATH}/m2net_conf/m2x2_SiNWFET.conf\n";
print $CONF_HANDLE "mpack2_arch = K6_pattern7_I24.arch\n";
print $CONF_HANDLE "power_tech_xml = $opt_ptr->{power_property_xml_val} # Use relative path under VPR folder is OK\n";
print $CONF_HANDLE "\n";
print $CONF_HANDLE "[csv_tags]\n";
print $CONF_HANDLE "mpack1_tags = Global mapping efficiency:|efficiency:|occupancy wo buf:|efficiency wo buf:\n";
print $CONF_HANDLE "mpack2_tags = BLE Number:|BLE Fill Rate: \n";
print $CONF_HANDLE "vpr_tags = Netlist clb blocks:|Final critical path:|Total logic delay:|total net delay:|Total routing area:|Total used logic block area:|Total wirelength:|Packing took|Placement took|Routing took|Average net density:|Median net density:|Recommend no. of clock cycles:\n";
print $CONF_HANDLE "vpr_power_tags = PB Types|Routing|Switch Box|Connection Box|Primitives|Interc Structures|lut6|ff\n";
return 1;
}
# Closes the file after being used
sub close_file($)
{
close ($CONF_HANDLE) || warn "close failed: $!";
return 1;
sub close_file($) {
close ($CONF_HANDLE) || warn "close failed: $!";
return 1;
}
# Input program path is like "~/program_dir/program_name"
# We split it from the scalar
sub split_prog_path($) {
my ($prog_path) = @_;
my @path_elements = split /\//,$prog_path;
my ($prog_dir,$prog_name);
$prog_name = $path_elements[$#path_elements];
$prog_dir = $prog_path;
$prog_dir =~ s/$prog_name$//g;
return ($prog_dir,$prog_name);
}
# Main routine
sub main()
{
&print_usage();
&generate_path($CONFIG_PATH);
&open_file($CONFIG_PATH);
&generate_file($CONFIG_PATH);
&close_file($CONFIG_PATH);
return 1;
sub main() {
&opts_read();
$CONFIG_FILEPATH = $opt_ptr->{output_conf_val};
my ($CONFIG_DIR_PATH, $CONFIG_FILENAME) = &split_prog_path($CONFIG_FILEPATH);
&generate_path($CONFIG_DIR_PATH);
&open_file($CONFIG_FILEPATH);
&generate_file($CONFIG_FILEPATH);
&close_file($CONFIG_FILEPATH);
print "Configuration file $CONFIG_FILEPATH generated!\n";
return 1;
}
&main();

29
yosys/.gitignore vendored Normal file
View File

@ -0,0 +1,29 @@
*.o
*.d
.*.swp
/.cproject
/.project
/.settings
/qtcreator.files
/qtcreator.includes
/qtcreator.config
/qtcreator.creator
/qtcreator.creator.user
/Makefile.conf
/abc
/viz.js
/yosys
/yosys.exe
/yosys.js
/yosys-abc
/yosys-abc.exe
/yosys-config
/yosys-smtbmc
/yosys-filterlib
/yosys-filterlib.exe
/kernel/version_*.cc
/share
/yosys-win32-mxebin-*
/yosys-win32-vcxsrc-*
/yosysjs-*
/libyosys.so

34
yosys/.travis.yml Normal file
View File

@ -0,0 +1,34 @@
sudo: false
script: make && make test
language: cpp
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gperf
- build-essential
- clang
- bison
- flex
- libreadline-dev
- gawk
- tcl-dev
- libffi-dev
- git
- mercurial
- graphviz
- xdot
- pkg-config
- python
- g++-4.8
before_install:
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
- git clone git://github.com/steveicarus/iverilog.git
- (cd iverilog && autoconf && ./configure --prefix=$HOME/iverilog && make && make install)
- export PATH=$PATH:$HOME/iverilog/bin
compiler:
# - clang
- gcc
os:
- linux

489
yosys/CHANGELOG Normal file
View File

@ -0,0 +1,489 @@
List of major changes and improvements between releases
=======================================================
Yosys 0.6 .. Yosys 0.7
----------------------
* Various
- Added "yosys -D" feature
- Added support for installed plugins in $(DATDIR)/plugins/
- Renamed opt_const to opt_expr
- Renamed opt_share to opt_merge
- Added "prep -flatten" and "synth -flatten"
- Added "prep -auto-top" and "synth -auto-top"
- Using "mfs" and "lutpack" in ABC lut mapping
- Support for abstract modules in chparam
- Cleanup abstract modules at end of "hierarchy -top"
- Added tristate buffer support to iopadmap
- Added opt_expr support for div/mod by power-of-two
- Added "select -assert-min <N> -assert-max <N>"
- Added "attrmvcp" pass
- Added "attrmap" command
- Added "tee +INT -INT"
- Added "zinit" pass
- Added "setparam -type"
- Added "shregmap" pass
- Added "setundef -init"
- Added "nlutmap -assert"
- Added $sop cell type and "abc -sop -I <num> -P <num>"
- Added "dc2" to default ABC scripts
- Added "deminout"
- Added "insbuf" command
- Added "prep -nomem"
- Added "opt_rmdff -keepdc"
- Added "prep -nokeepdc"
- Added initial version of "synth_gowin"
- Added "fsm_expand -full"
- Added support for fsm_encoding="user"
- Many improvements in GreenPAK4 support
- Added black box modules for all Xilinx 7-series lib cells
- Added synth_ice40 support for latches via logic loops
- Fixed ice40_opt lut unmapping, added "ice40_opt -unlut"
* Build System
- Added ABCEXTERNAL and ABCURL make variables
- Added BINDIR, LIBDIR, and DATDIR make variables
- Added PKG_CONFIG make variable
- Added SEED make variable (for "make test")
- Added YOSYS_VER_STR make variable
- Updated min GCC requirement to GCC 4.8
- Updated required Bison version to Bison 3.x
* Internal APIs
- Added ast.h to exported headers
- Added ScriptPass helper class for script-like passes
- Added CellEdgesDatabase API
* Front-ends and Back-ends
- Added filename glob support to all front-ends
- Added avail (black-box) module params to ilang format
- Added $display %m support
- Added support for $stop Verilog system task
- Added support for SystemVerilog packages
- Fixed procedural assignments to non-unique lvalues, e.g. {y,y} = {a,b}
- Added support for "active high" and "active low" latches in read_blif and write_blif
- Use init value "2" for all uninitialized FFs in BLIF back-end
- Added "read_blif -sop"
- Added "write_blif -noalias"
- Added various write_blif options for VTR support
- write_json: also write module attributes.
- Added "write_verilog -nodec -nostr -defparam"
- Added "read_verilog -norestrict -assume-asserts"
- Added support for bus interfaces to "read_liberty -lib"
- Added liberty parser support for types within cell decls
- Added "write_verilog -renameprefix -v"
- Added "write_edif -nogndvcc"
* Formal Verification
- Support for hierarchical designs in smt2 back-end
- Yosys-smtbmc: Support for hierarchical VCD dumping
- Added $initstate cell type and vlog function
- Added $anyconst and $anyseq cell types and vlog functions
- Added printing of code loc of failed asserts to yosys-smtbmc
- Added memory_memx pass, "memory -memx", and "prep -memx"
- Added "proc_mux -ifx"
- Added "yosys-smtbmc -g"
- Deprecated "write_smt2 -regs" (by default on now)
- Made "write_smt2 -bv -mem" default, added "write_smt2 -nobv -nomem"
- Added support for memories to smtio.py
- Added "yosys-smtbmc --dump-vlogtb"
- Added "yosys-smtbmc --smtc --dump-smtc"
- Added "yosys-smtbmc --dump-all"
- Added assertpmux command
- Added "yosys-smtbmc --unroll"
- Added $past, $stable, $rose, $fell SVA functions
- Added "yosys-smtbmc --noinfo and --dummy"
- Added "yosys-smtbmc --noincr"
- Added "yosys-smtbmc --cex <filename>"
- Added $ff and $_FF_ cell types
- Added $global_clock verilog syntax support for creating $ff cells
- Added clk2fflogic
Yosys 0.5 .. Yosys 0.6
----------------------
* Various
- Added Contributor Covenant Code of Conduct
- Various improvements in dict<> and pool<>
- Added hashlib::mfp and refactored SigMap
- Improved support for reals as module parameters
- Various improvements in SMT2 back-end
- Added "keep_hierarchy" attribute
- Verilog front-end: define `BLACKBOX in -lib mode
- Added API for converting internal cells to AIGs
- Added ENABLE_LIBYOSYS Makefile option
- Removed "techmap -share_map" (use "-map +/filename" instead)
- Switched all Python scripts to Python 3
- Added support for $display()/$write() and $finish() to Verilog front-end
- Added "yosys-smtbmc" formal verification flow
- Added options for clang sanitizers to Makefile
* New commands and options
- Added "scc -expect <N> -nofeedback"
- Added "proc_dlatch"
- Added "check"
- Added "select %xe %cie %coe %M %C %R"
- Added "sat -dump_json" (WaveJSON format)
- Added "sat -tempinduct-baseonly -tempinduct-inductonly"
- Added "sat -stepsize" and "sat -tempinduct-step"
- Added "sat -show-regs -show-public -show-all"
- Added "write_json" (Native Yosys JSON format)
- Added "write_blif -attr"
- Added "dffinit"
- Added "chparam"
- Added "muxcover"
- Added "pmuxtree"
- Added memory_bram "make_outreg" feature
- Added "splice -wires"
- Added "dff2dffe -direct-match"
- Added simplemap $lut support
- Added "read_blif"
- Added "opt_share -share_all"
- Added "aigmap"
- Added "write_smt2 -mem -regs -wires"
- Added "memory -nordff"
- Added "write_smv"
- Added "synth -nordff -noalumacc"
- Added "rename -top new_name"
- Added "opt_const -clkinv"
- Added "synth -nofsm"
- Added "miter -assert"
- Added "read_verilog -noautowire"
- Added "read_verilog -nodpi"
- Added "tribuf"
- Added "lut2mux"
- Added "nlutmap"
- Added "qwp"
- Added "test_cell -noeval"
- Added "edgetypes"
- Added "equiv_struct"
- Added "equiv_purge"
- Added "equiv_mark"
- Added "equiv_add -try -cell"
- Added "singleton"
- Added "abc -g -luts"
- Added "torder"
- Added "write_blif -cname"
- Added "submod -copy"
- Added "dffsr2dff"
- Added "stat -liberty"
* Synthesis metacommands
- Various improvements in synth_xilinx
- Added synth_ice40 and synth_greenpak4
- Added "prep" metacommand for "synthesis lite"
* Cell library changes
- Added cell types to "help" system
- Added $meminit cell type
- Added $assume cell type
- Added $_MUX4_, $_MUX8_, and $_MUX16_ cells
- Added $tribuf and $_TBUF_ cell types
- Added read-enable to memory model
* YosysJS
- Various improvements in emscripten build
- Added alternative webworker-based JS API
- Added a few example applications
Yosys 0.4 .. Yosys 0.5
----------------------
* API changes
- Added log_warning()
- Added eval_select_args() and eval_select_op()
- Added cell->known(), cell->input(portname), cell->output(portname)
- Skip blackbox modules in design->selected_modules()
- Replaced std::map<> and std::set<> with dict<> and pool<>
- New SigSpec::extend() is what used to be SigSpec::extend_u0()
- Added YS_OVERRIDE, YS_FINAL, YS_ATTRIBUTE, YS_NORETURN
* Cell library changes
- Added flip-flops with enable ($dffe etc.)
- Added $equiv cells for equivalence checking framework
* Various
- Updated ABC to hg rev 61ad5f908c03
- Added clock domain partitioning to ABC pass
- Improved plugin building (see "yosys-config --build")
- Added ENABLE_NDEBUG Makefile flag for high-performance builds
- Added "yosys -d", "yosys -L" and other driver improvements
- Added support for multi-bit (array) cell ports to "write_edif"
- Now printing most output to stdout, not stderr
- Added "onehot" attribute (set by "fsm_map")
- Various performance improvements
- Vastly improved Xilinx flow
- Added "make unsintall"
* Equivalence checking
- Added equivalence checking commands:
equiv_make equiv_simple equiv_status
equiv_induct equiv_miter
equiv_add equiv_remove
* Block RAM support:
- Added "memory_bram" command
- Added BRAM support to Xilinx flow
* Other New Commands and Options
- Added "dff2dffe"
- Added "fsm -encfile"
- Added "dfflibmap -prepare"
- Added "write_blid -unbuf -undef -blackbox"
- Added "write_smt2" for writing SMT-LIBv2 files
- Added "test_cell -w -muxdiv"
- Added "select -read"
Yosys 0.3.0 .. Yosys 0.4
------------------------
* Platform Support
- Added support for mxe-based cross-builds for win32
- Added sourcecode-export as VisualStudio project
- Added experimental EMCC (JavaScript) support
* Verilog Frontend
- Added -sv option for SystemVerilog (and automatic *.sv file support)
- Added support for real-valued constants and constant expressions
- Added support for non-standard "via_celltype" attribute on task/func
- Added support for non-standard "module mod_name(...);" syntax
- Added support for non-standard """ macro bodies
- Added support for array with more than one dimension
- Added support for $readmemh and $readmemb
- Added support for DPI functions
* Changes in internal cell library
- Added $shift and $shiftx cell types
- Added $alu, $lcu, $fa and $macc cell types
- Removed $bu0 and $safe_pmux cell types
- $mem/$memwr WR_EN input is now a per-data-bit enable signal
- Added $_NAND_ $_NOR_ $_XNOR_ $_AOI3_ $_OAI3_ $_AOI4_ $_OAI4_
- Renamed ports of $lut cells (from I->O to A->Y)
- Renamed $_INV_ to $_NOT_
* Changes for simple synthesis flows
- There is now a "synth" command with a recommended default script
- Many improvements in synthesis of arithmetic functions to gates
- Multipliers and adders with many operands are using carry-save adder trees
- Remaining adders are now implemented using Brent-Kung carry look-ahead adders
- Various new high-level optimizations on RTL netlist
- Various improvements in FSM optimization
- Updated ABC to hg 5b5af75f1dda (from 2014-11-07)
* Changes in internal APIs and RTLIL
- Added log_id() and log_cell() helper functions
- Added function-like cell creation helpers
- Added GetSize() function (like .size() but with int)
- Major refactoring of RTLIL::Module and related classes
- Major refactoring of RTLIL::SigSpec and related classes
- Now RTLIL::IdString is essentially an int
- Added macros for code coverage counters
- Added some Makefile magic for pretty make logs
- Added "kernel/yosys.h" with all the core definitions
- Changed a lot of code from FILE* to c++ streams
- Added RTLIL::Monitor API and "trace" command
- Added "Yosys" C++ namespace
* Changes relevant to SAT solving
- Added ezSAT::keep_cnf() and ezSAT::non_incremental()
- Added native ezSAT support for vector shift ops
- Updated MiniSAT to git 37dc6c67e2 (from 2013-09-25)
* New commands (or large improvements to commands)
- Added "synth" command with default script
- Added "share" (finally some real resource sharing)
- Added "memory_share" (reduce number of ports on memories)
- Added "wreduce" and "alumacc" commands
- Added "opt -keepdc -fine -full -fast"
- Added some "test_*" commands
* Various other changes
- Added %D and %c select operators
- Added support for labels in yosys scripts
- Added support for here-documents in yosys scripts
- Support "+/" prefix for files from proc_share_dir
- Added "autoidx" statement to ilang language
- Switched from "yosys-svgviewer" to "xdot"
- Renamed "stdcells.v" to "techmap.v"
- Various bug fixes and small improvements
- Improved welcome and bye messages
Yosys 0.2.0 .. Yosys 0.3.0
--------------------------
* Driver program and overall behavior:
- Added "design -push" and "design -pop"
- Added "tee" command for redirecting log output
* Changes in the internal cell library:
- Added $dlatchsr and $_DLATCHSR_???_ cell types
* Improvements in Verilog frontend:
- Improved support for const functions (case, always, repeat)
- The generate..endgenerate keywords are now optional
- Added support for arrays of module instances
- Added support for "`default_nettype" directive
- Added support for "`line" directive
* Other front- and back-ends:
- Various changes to "write_blif" options
- Various improvements in EDIF backend
- Added "vhdl2verilog" pseudo-front-end
- Added "verific" pseudo-front-end
* Improvements in technology mapping:
- Added support for recursive techmap
- Added CONSTMSK and CONSTVAL features to techmap
- Added _TECHMAP_CONNMAP_*_ feature to techmap
- Added _TECHMAP_REPLACE_ feature to techmap
- Added "connwrappers" command for wrap-extract-unwrap method
- Added "extract -map %<design_name>" feature
- Added "extract -ignore_param ..." and "extract -ignore_parameters"
- Added "techmap -max_iter" option
* Improvements to "eval" and "sat" framework:
- Now include a copy of Minisat (with build fixes applied)
- Switched to Minisat::SimpSolver as SAT back-end
- Added "sat -dump_vcd" feature
- Added "sat -dump_cnf" feature
- Added "sat -initsteps <N>" feature
- Added "freduce -stop <N>" feature
- Added "freduce -dump <prefix>" feature
* Integration with ABC:
- Updated ABC rev to 7600ffb9340c
* Improvements in the internal APIs:
- Added RTLIL::Module::add... helper methods
- Various build fixes for OSX (Darwin) and OpenBSD
Yosys 0.1.0 .. Yosys 0.2.0
--------------------------
* Changes to the driver program:
- Added "yosys -h" and "yosys -H"
- Added support for backslash line continuation in scripts
- Added support for #-comments in same line as command
- Added "echo" and "log" commands
* Improvements in Verilog frontend:
- Added support for local registers in named blocks
- Added support for "case" in "generate" blocks
- Added support for $clog2 system function
- Added support for basic SystemVerilog assert statements
- Added preprocessor support for macro arguments
- Added preprocessor support for `elsif statement
- Added "verilog_defaults" command
- Added read_verilog -icells option
- Added support for constant sizes from parameters
- Added "read_verilog -setattr"
- Added support for function returning 'integer'
- Added limited support for function calls in parameter values
- Added "read_verilog -defer" to suppress evaluation of modules with default parameters
* Other front- and back-ends:
- Added BTOR backend
- Added Liberty frontend
* Improvements in technology mapping:
- The "dfflibmap" command now strongly prefers solutions with
no inverters in clock paths
- The "dfflibmap" command now prefers cells with smaller area
- Added support for multiple -map options to techmap
- Added "dfflibmap" support for //-comments in liberty files
- Added "memory_unpack" command to revert "memory_collect"
- Added standard techmap rule "techmap -share_map pmux2mux.v"
- Added "iopadmap -bits"
- Added "setundef" command
- Added "hilomap" command
* Changes in the internal cell library:
- Major rewrite of simlib.v for better compatibility with other tools
- Added PRIORITY parameter to $memwr cells
- Added TRANSPARENT parameter to $memrd cells
- Added RD_TRANSPARENT parameter to $mem cells
- Added $bu0 cell (always 0-extend, even undef MSB)
- Added $assert cell type
- Added $slice and $concat cell types
* Integration with ABC:
- Updated ABC to hg rev 2058c8ccea68
- Tighter integration of ABC build with Yosys build. The make
targets 'make abc' and 'make install-abc' are now obsolete.
- Added support for passing FFs from one clock domain through ABC
- Now always use BLIF as exchange format with ABC
- Added support for "abc -script +<command_sequence>"
- Improved standard ABC recipe
- Added support for "keep" attribute to abc command
- Added "abc -dff / -clk / -keepff" options
* Improvements to "eval" and "sat" framework:
- Added support for "0" and "~0" in right-hand side -set expressions
- Added "eval -set-undef" and "eval -table"
- Added "sat -set-init" and "sat -set-init-*" for sequential problems
- Added undef support to SAT solver, incl. various new "sat" options
- Added correct support for === and !== for "eval" and "sat"
- Added "sat -tempinduct" (default -seq is now non-induction sequential)
- Added "sat -prove-asserts"
- Complete rewrite of the 'freduce' command
- Added "miter" command
- Added "sat -show-inputs" and "sat -show-outputs"
- Added "sat -ignore_unknown_cells" (now produce an error by default)
- Added "sat -falsify"
- Now "sat -verify" and "sat -falsify" can also be used without "-prove"
- Added "expose" command
- Added support for @<sel_name> to sat and eval signal expressions
* Changes in the 'make test' framework and auxiliary test tools:
- Added autotest.sh -p and -f options
- Replaced autotest.sh ISIM support with XSIM support
- Added test cases for SAT framework
* Added "abbreviated IDs":
- Now $<something>$foo can be abbreviated as $foo.
- Usually this last part is a unique id (from RTLIL::autoidx)
- This abbreviated IDs are now also used in "show" output
* Other changes to selection framework:
- Now */ is optional in */<mode>:<arg> expressions
- Added "select -assert-none" and "select -assert-any"
- Added support for matching modules by attribute (A:<expr>)
- Added "select -none"
- Added support for r:<expr> pattern for matching cell parameters
- Added support for !=, <, <=, >=, > for attribute and parameter matching
- Added support for %s for selecting sub-modules
- Added support for %m for expanding selections to whole modules
- Added support for i:*, o:* and x:* pattern for selecting module ports
- Added support for s:<expr> pattern for matching wire width
- Added support for %a operation to select wire aliases
* Various other changes to commands and options:
- The "ls" command now supports wildcards
- Added "show -pause" and "show -format dot"
- Added "show -color" support for cells
- Added "show -label" and "show -notitle"
- Added "dump -m" and "dump -n"
- Added "history" command
- Added "rename -hide"
- Added "connect" command
- Added "splitnets -driver"
- Added "opt_const -mux_undef"
- Added "opt_const -mux_bool"
- Added "opt_const -undriven"
- Added "opt -mux_undef -mux_bool -undriven -purge"
- Added "hierarchy -libdir"
- Added "hierarchy -purge_lib" (by default now do not remove lib cells)
- Added "delete" command
- Added "dump -append"
- Added "setattr" and "setparam" commands
- Added "design -stash/-copy-from/-copy-to"
- Added "copy" command
- Added "splice" command

73
yosys/CodeOfConduct Normal file
View File

@ -0,0 +1,73 @@
Contributor Covenant Code of Conduct
Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at clifford@clifford.at (and/or
cliffordvienna@gmail.com if you think your mail to the other address got
stuck in the spam filter). All complaints will be reviewed and investigated and
will result in a response that is deemed necessary and appropriate to the
circumstances. The project team is obligated to maintain confidentiality with
regard to the reporter of an incident. Further details of specific enforcement
policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
Attribution
This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
available at http://contributor-covenant.org/version/1/4/

413
yosys/CodingReadme Normal file
View File

@ -0,0 +1,413 @@
This file contains some very brief documentation on things like programming APIs.
Also consult the Yosys manual and the section about programming in the presentation.
(Both can be downloaded as PDF from the yosys webpage.)
--snip-- only the lines below this mark are included in the yosys manual --snip--
Getting Started
===============
Outline of a Yosys command
--------------------------
Here is a the C++ code for a "hello_world" Yosys command (hello.cc):
#include "kernel/yosys.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct HelloWorldPass : public Pass {
HelloWorldPass() : Pass("hello_world") { }
virtual void execute(vector<string>, Design*) {
log("Hello World!\n");
}
} HelloWorldPass;
PRIVATE_NAMESPACE_END
This can be built into a Yosys module using the following command:
yosys-config --exec --cxx --cxxflags --ldflags -o hello.so -shared hello.cc --ldlibs
Or short:
yosys-config --build hello.so hello.cc
And then executed using the following command:
yosys -m hello.so -p hello_world
Yosys Data Structures
---------------------
Here is a short list of data structures that you should make yourself familiar
with before you write C++ code for Yosys. The following data structures are all
defined when "kernel/yosys.h" is included and USING_YOSYS_NAMESPACE is used.
1. Yosys Container Classes
Yosys uses dict<K, T> and pool<T> as main container classes. dict<K, T> is
essentially a replacement for std::unordered_map<K, T> and pool<T> is a
replacement for std::unordered_set<T>. The main characteristics are:
- dict<K, T> and pool<T> are about 2x faster than the std containers
- references to elements in a dict<K, T> or pool<T> are invalidated by
insert and remove operations (similar to std::vector<T> on push_back()).
- some iterators are invalidated by erase(). specifically, iterators
that have not passed the erased element yet are invalidated. (erase()
itself returns valid iterator to the next element.)
- no iterators are invalidated by insert(). elements are inserted at
begin(). i.e. only a new iterator that starts at begin() will see the
inserted elements.
- the method .count(key, iterator) is like .count(key) but only
considers elements that can be reached via the iterator.
- iterators can be compared. it1 < it2 means that the position of t2
can be reached via t1 but not vice versa.
- the method .sort() can be used to sort the elements in the container
the container stays sorted until elements are added or removed.
- dict<K, T> and pool<T> will have the same order of iteration across
all compilers, standard libraries and architectures.
In addition to dict<K, T> and pool<T> there is also an idict<K> that
creates a bijective map from K to the integers. For example:
idict<string, 42> si;
log("%d\n", si("hello")); // will print 42
log("%d\n", si("world")); // will print 43
log("%d\n", si.at("world")); // will print 43
log("%d\n", si.at("dummy")); // will throw exception
log("%s\n", si[42].c_str())); // will print hello
log("%s\n", si[43].c_str())); // will print world
log("%s\n", si[44].c_str())); // will throw exception
It is not possible to remove elements from an idict.
Finally mfp<K> implements a merge-find set data structure (aka. disjoint-set or
union-find) over the type K ("mfp" = merge-find-promote).
2. Standard STL data types
In Yosys we use std::vector<T> and std::string whenever applicable. When
dict<K, T> and pool<T> are not suitable then std::map<K, T> and std::set<T>
are used instead.
The types std::vector<T> and std::string are also available as vector<T>
and string in the Yosys namespace.
3. RTLIL objects
The current design (essentially a collection of modules, each defined by a
netlist) is stored in memory using RTLIL object (declared in kernel/rtlil.h,
automatically included by kernel/yosys.h). You should glance over at least
the declarations for the following types in kernel/rtlil.h:
RTLIL::IdString
This is a handle for an identifier (e.g. cell or wire name).
It feels a lot like a std::string, but is only a single int
in size. (The actual string is stored in a global lookup
table.)
RTLIL::SigBit
A single signal bit. I.e. either a constant state (0, 1,
x, z) or a single bit from a wire.
RTLIL::SigSpec
Essentially a vector of SigBits.
RTLIL::Wire
RTLIL::Cell
The building blocks of the netlist in a module.
RTLIL::Module
RTLIL::Design
The module is a container with connected cells and wires
in it. The design is a container with modules in it.
All this types are also available without the RTLIL:: prefix in the Yosys
namespace.
4. SigMap and other Helper Classes
There are a couple of additional helper classes that are in wide use
in Yosys. Most importantly there is SigMap (declared in kernel/sigtools.h).
When a design has many wires in it that are connected to each other, then a
single signal bit can have multiple valid names. The SigMap object can be used
to map SigSpecs or SigBits to unique SigSpecs and SigBits that consistently
only use one wire from such a group of connected wires. For example:
SigBit a = module->addWire(NEW_ID);
SigBit b = module->addWire(NEW_ID);
module->connect(a, b);
log("%d\n", a == b); // will print 0
SigMap sigmap(module);
log("%d\n", sigmap(a) == sigmap(b)); // will print 1
Using the RTLIL Netlist Format
------------------------------
In the RTLIL netlist format the cell ports contain SigSpecs that point to the
Wires. There are no references in the other direction. This has two direct
consequences:
(1) It is very easy to go from cells to wires but hard to go in the other way.
(2) There is no danger in removing cells from the netlists, but removing wires
can break the netlist format when there are still references to the wire
somewhere in the netlist.
The solution to (1) is easy: Create custom indexes that allow you to make fast
lookups for the wire-to-cell direction. You can either use existing generic
index structures to do that (such as the ModIndex class) or write your own
index. For many application it is simplest to construct a custom index. For
example:
SigMap sigmap(module);
dict<SigBit, Cell*> sigbit_to_driver_index;
for (auto cell : module->cells())
for (auto &conn : cell->connections())
if (cell->output(conn.first))
for (auto bit : sigmap(conn.second))
sigbit_to_driver_index[bit] = cell;
Regarding (2): There is a general theme in Yosys that you don't remove wires
from the design. You can rename them, unconnect them, but you do not actually remove
the Wire object from the module. Instead you let the "clean" command take care
of the dangling wires. On the other hand it is safe to remove cells (as long as
you make sure this does not invalidate a custom index you are using in your code).
Example Code
------------
The following yosys commands are a good starting point if you are looking for examples
of how to use the Yosys API:
manual/CHAPTER_Prog/stubnets.cc
manual/PRESENTATION_Prog/my_cmd.cc
Notes on the existing codebase
------------------------------
For historical reasons not all parts of Yosys adhere to the current coding
style. When adding code to existing parts of the system, adhere to this guide
for the new code instead of trying to mimic the style of the surrounding code.
Coding Style
============
Formatting of code
------------------
- Yosys code is using tabs for indentation. Tabs are 8 characters.
- A continuation of a statement in the following line is indented by
two additional tabs.
- Lines are as long as you want them to be. A good rule of thumb is
to break lines at about column 150.
- Opening braces can be put on the same or next line as the statement
opening the block (if, switch, for, while, do). Put the opening brace
on its own line for larger blocks, especially blocks that contains
blank lines.
- Otherwise stick to the Linux Kernel Coding Style:
https://www.kernel.org/doc/Documentation/CodingStyle
C++ Language
-------------
Yosys is written in C++11. At the moment only constructs supported by
gcc 4.8 are allowed in Yosys code. This will change in future releases.
In general Yosys uses "int" instead of "size_t". To avoid compiler
warnings for implicit type casts, always use "GetSize(foobar)" instead
of "foobar.size()". (GetSize() is defined in kernel/yosys.h)
Use range-based for loops whenever applicable.
--snap-- only the lines above this mark are included in the yosys manual --snap--
Creating the Visual Studio Template Project
===========================================
1. Create an empty Visual C++ Win32 Console App project
Microsoft Visual Studio Express 2013 for Windows Desktop
Open New Project Wizard (File -> New Project..)
Project Name: YosysVS
Solution Name: YosysVS
[X] Create directory for solution
[ ] Add to source control
[X] Console applications
[X] Empty Project
[ ] SDL checks
2. Open YosysVS Project Properties
Select Configuration: All Configurations
C/C++ -> General -> Additional Include Directories
Add: ..\yosys
C/C++ -> Preprocessor -> Preprocessor Definitions
Add: _YOSYS_;_CRT_SECURE_NO_WARNINGS
3. Resulting file system tree:
YosysVS/
YosysVS/YosysVS
YosysVS/YosysVS/YosysVS.vcxproj
YosysVS/YosysVS/YosysVS.vcxproj.filters
YosysVS/YosysVS.sdf
YosysVS/YosysVS.sln
YosysVS/YosysVS.v12.suo
4. Zip YosysVS as YosysVS-Tpl-v1.zip
Checklist for adding internal cell types
========================================
Things to do right away:
- Add to kernel/celltypes.h (incl. eval() handling for non-mem cells)
- Add to InternalCellChecker::check() in kernel/rtlil.cc
- Add to techlibs/common/simlib.v
- Add to techlibs/common/techmap.v
Things to do after finalizing the cell interface:
- Add support to kernel/satgen.h for the new cell type
- Add to manual/CHAPTER_CellLib.tex (or just add a fixme to the bottom)
- Maybe add support to the Verilog backend for dumping such cells as expression
Checklist for creating Yosys releases
=====================================
Update the CHANGELOG file:
cd ~yosys
gitk &
vi CHANGELOG
Update and check documentation:
cd ~yosys
make update-manual
make manual
- sanity check the figures in the appnotes and presentation
- if there are any odd things -> investigate
- make cosmetic changes to the .tex files if necessary
cd ~yosys
vi README CodingReadme
- is the information provided in those file still up to date
Then with default config setting:
cd ~yosys
make vgtest
cd ~yosys
./yosys -p 'proc; show' tests/simple/fiedler-cooley.v
./yosys -p 'proc; opt; show' tests/simple/fiedler-cooley.v
./yosys -p 'synth; show' tests/simple/fiedler-cooley.v
./yosys -p 'synth_xilinx -top up3down5; show' tests/simple/fiedler-cooley.v
cd ~yosys/examples/cmos
bash testbench.sh
cd ~yosys/examples/basys3
bash run.sh
Test building plugins with various of the standard passes:
yosys-config --build test.so equiv_simple.cc
- also check the code examples in CodingReadme
And if a version of the verific library is currently available:
cd ~yosys
cat frontends/verific/build_amd64.txt
- follow instructions
cd frontends/verific
../../yosys test_navre.ys
Finally run all tests with "make config-{clang,gcc,gcc-4.8}":
cd ~yosys
make clean
make test
make vloghtb
make install
cd ~yosys-bigsim
make clean
make full
cd ~vloghammer
make purge gen_issues gen_samples
make SYN_LIST="yosys" SIM_LIST="icarus yosim verilator" REPORT_FULL=1 world
chromium-browser report.html
Release:
- set YOSYS_VER to x.y.z in Makefile
- update version string in CHANGELOG
git commit -am "Yosys x.y.z"
- push tag to github
- post changelog on github
- post short release note on reddit
Updating the website:
cd ~yosys
make manual
make install
- update pdf files on the website
cd ~yosys-web
make update_cmd
make update_show
git commit -am update
make push

565
yosys/Makefile Normal file
View File

@ -0,0 +1,565 @@
#CONFIG := clang
CONFIG := gcc
# CONFIG := gcc-4.8
# CONFIG := emcc
# CONFIG := mxe
# CONFIG := msys2
# features (the more the better)
ENABLE_TCL := 1
ENABLE_ABC := 1
ENABLE_PLUGINS := 1
ENABLE_READLINE := 1
ENABLE_VERIFIC := 0
ENABLE_COVER := 1
ENABLE_LIBYOSYS := 0
# other configuration flags
ENABLE_GPROF := 0
ENABLE_NDEBUG := 0
# clang sanitizers
SANITIZER =
# SANITIZER = address
# SANITIZER = memory
# SANITIZER = undefined
# SANITIZER = cfi
PREFIX ?= /usr/local
INSTALL_SUDO :=
BINDIR := $(PREFIX)/bin
LIBDIR := $(PREFIX)/lib
DATDIR := $(PREFIX)/share/yosys
EXE =
OBJS =
GENFILES =
EXTRA_OBJS =
EXTRA_TARGETS =
TARGETS = yosys$(EXE) yosys-config
PRETTY = 1
SMALL = 0
all: top-all
YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST)))
VPATH := $(YOSYS_SRC)
CXXFLAGS += -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(PREFIX)/include
LDFLAGS += -L$(LIBDIR)
LDLIBS = -lstdc++ -lm
PKG_CONFIG = pkg-config
SED = sed
BISON = bison
ifeq (Darwin,$(findstring Darwin,$(shell uname)))
# add macports/homebrew include and library path to search directories, don't use '-rdynamic' and '-lrt':
CXXFLAGS += -I/opt/local/include -I/usr/local/opt/readline/include
LDFLAGS += -L/opt/local/lib -L/usr/local/opt/readline/lib
# add homebrew's libffi include and library path
CXXFLAGS += $(shell PKG_CONFIG_PATH=$$(brew list libffi | grep pkgconfig | xargs dirname) pkg-config --silence-errors --cflags libffi)
LDFLAGS += $(shell PKG_CONFIG_PATH=$$(brew list libffi | grep pkgconfig | xargs dirname) pkg-config --silence-errors --libs libffi)
# use bison installed by homebrew if available
BISON = $(shell (brew list bison | grep -m1 "bin/bison") || echo bison)
SED = sed
else
LDFLAGS += -rdynamic
LDLIBS += -lrt
endif
YOSYS_VER := 0.7
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
OBJS = kernel/version_$(GIT_REV).o
# set 'ABCREV = default' to use abc/ as it is
#
# Note: If you do ABC development, make sure that 'abc' in this directory
# is just a symlink to your actual ABC working directory, as 'make mrproper'
# will remove the 'abc' directory and you do not want to accidentally
# delete your work on ABC..
ABCREV = ae6716b
ABCPULL = 1
ABCURL ?= https://github.com/berkeley-abc/abc
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1
# set ABCEXTERNAL = <abc-command> to use an external ABC instance
# Note: The in-tree ABC (yosys-abc) will not be installed when ABCEXTERNAL is set.
ABCEXTERNAL ?=
define newline
endef
ifneq ($(wildcard Makefile.conf),)
$(info $(subst $$--$$,$(newline),$(shell sed 's,^,[Makefile.conf] ,; s,$$,$$--$$,;' < Makefile.conf | tr -d '\n' | sed 's,\$$--\$$$$,,')))
include Makefile.conf
endif
ifeq ($(CONFIG),clang)
CXX = clang
LD = clang++
CXXFLAGS += -std=c++11 -Os
ifneq ($(SANITIZER),)
$(info [Clang Sanitizer] $(SANITIZER))
CXXFLAGS += -g -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=$(SANITIZER)
LDFLAGS += -g -fsanitize=$(SANITIZER)
ifeq ($(SANITIZER),address)
ENABLE_COVER := 0
endif
ifeq ($(SANITIZER),memory)
CXXFLAGS += -fPIE -fsanitize-memory-track-origins
LDFLAGS += -fPIE -fsanitize-memory-track-origins
endif
ifeq ($(SANITIZER),cfi)
CXXFLAGS += -flto
LDFLAGS += -flto
endif
endif
else ifeq ($(CONFIG),gcc)
CXX = gcc
LD = gcc
CXXFLAGS += -std=c++11 -Os
else ifeq ($(CONFIG),gcc-4.8)
CXX = gcc-4.8
LD = gcc-4.8
CXXFLAGS += -std=c++11 -Os
else ifeq ($(CONFIG),emcc)
CXX = emcc
LD = emcc
CXXFLAGS := -std=c++11 $(filter-out -fPIC -ggdb,$(CXXFLAGS))
EMCCFLAGS := -Os -Wno-warn-absolute-paths
EMCCFLAGS += --memory-init-file 0 --embed-file share -s NO_EXIT_RUNTIME=1
EMCCFLAGS += -s EXPORTED_FUNCTIONS="['_main','_run','_prompt','_errmsg']"
EMCCFLAGS += -s TOTAL_MEMORY=128*1024*1024
# https://github.com/kripken/emscripten/blob/master/src/settings.js
CXXFLAGS += $(EMCCFLAGS)
LDFLAGS += $(EMCCFLAGS)
LDLIBS =
EXE = .js
TARGETS := $(filter-out yosys-config,$(TARGETS))
EXTRA_TARGETS += yosysjs-$(YOSYS_VER).zip
viz.js:
wget -O viz.js.part https://github.com/mdaines/viz.js/releases/download/0.0.3/viz.js
mv viz.js.part viz.js
yosysjs-$(YOSYS_VER).zip: yosys.js viz.js misc/yosysjs/*
rm -rf yosysjs-$(YOSYS_VER) yosysjs-$(YOSYS_VER).zip
mkdir -p yosysjs-$(YOSYS_VER)
cp viz.js misc/yosysjs/* yosys.js yosysjs-$(YOSYS_VER)/
zip -r yosysjs-$(YOSYS_VER).zip yosysjs-$(YOSYS_VER)
yosys.html: misc/yosys.html
$(P) cp misc/yosys.html yosys.html
else ifeq ($(CONFIG),mxe)
CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc
LD = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc
CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
LDLIBS := $(filter-out -lrt,$(LDLIBS))
ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -x c++ -fpermissive -w"
ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="$(CXX)" CXX="$(CXX)"
EXE = .exe
else ifeq ($(CONFIG),msys2)
CXX = i686-w64-mingw32-gcc
LD = i686-w64-mingw32-gcc
CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
LDLIBS := $(filter-out -lrt,$(LDLIBS))
ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -x c++ -fpermissive -w"
ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=0 CC="$(CXX)" CXX="$(CXX)"
EXE = .exe
else ifneq ($(CONFIG),none)
$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.8, emcc, mxe, msys2)
endif
ifeq ($(ENABLE_LIBYOSYS),1)
TARGETS += libyosys.so
endif
ifeq ($(ENABLE_READLINE),1)
CXXFLAGS += -DYOSYS_ENABLE_READLINE
LDLIBS += -lreadline
ifeq ($(CONFIG),mxe)
LDLIBS += -lpdcurses
endif
endif
ifeq ($(ENABLE_PLUGINS),1)
CXXFLAGS += -DYOSYS_ENABLE_PLUGINS $(shell $(PKG_CONFIG) --silence-errors --cflags libffi)
LDLIBS += $(shell $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) -ldl
endif
ifeq ($(ENABLE_TCL),1)
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
CXXFLAGS += -I$(TCL_INCLUDE) -DYOSYS_ENABLE_TCL
LDLIBS += -l$(TCL_VERSION)
endif
ifeq ($(ENABLE_GPROF),1)
CXXFLAGS += -pg
LDFLAGS += -pg
endif
ifeq ($(ENABLE_NDEBUG),1)
CXXFLAGS := -O3 -DNDEBUG $(filter-out -Os,$(CXXFLAGS))
endif
ifeq ($(ENABLE_ABC),1)
CXXFLAGS += -DYOSYS_ENABLE_ABC
ifeq ($(ABCEXTERNAL),)
TARGETS += yosys-abc$(EXE)
endif
endif
ifeq ($(ENABLE_VERIFIC),1)
VERIFIC_DIR ?= /usr/local/src/verific_lib_eval
VERIFIC_COMPONENTS ?= verilog vhdl database util containers sdf
CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC
LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS))
endif
ifeq ($(ENABLE_COVER),1)
CXXFLAGS += -DYOSYS_ENABLE_COVER
endif
define add_share_file
EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2)))
$(subst //,/,$(1)/$(notdir $(2))): $(2)
$$(P) mkdir -p $(1)
$$(Q) cp "$(YOSYS_SRC)"/$(2) $(subst //,/,$(1)/$(notdir $(2)))
endef
define add_gen_share_file
EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2)))
$(subst //,/,$(1)/$(notdir $(2))): $(2)
$$(P) mkdir -p $(1)
$$(Q) cp $(2) $(subst //,/,$(1)/$(notdir $(2)))
endef
define add_include_file
$(eval $(call add_share_file,$(dir share/include/$(1)),$(1)))
endef
ifeq ($(PRETTY), 1)
P_STATUS = 0
P_OFFSET = 0
P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys$(EXE) | gawk 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
P_SHOW = [$(shell gawk "BEGIN { N=$(words $(OBJS) yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%]
P = @echo "$(if $(findstring $@,$(TARGETS) $(EXTRA_TARGETS)),$(eval P_OFFSET = 10))$(call P_UPDATE)$(call P_SHOW) Building $@";
Q = @
S = -s
else
P_SHOW = ->
P =
Q =
S =
endif
$(eval $(call add_include_file,kernel/yosys.h))
$(eval $(call add_include_file,kernel/hashlib.h))
$(eval $(call add_include_file,kernel/log.h))
$(eval $(call add_include_file,kernel/rtlil.h))
$(eval $(call add_include_file,kernel/register.h))
$(eval $(call add_include_file,kernel/celltypes.h))
$(eval $(call add_include_file,kernel/celledges.h))
$(eval $(call add_include_file,kernel/consteval.h))
$(eval $(call add_include_file,kernel/sigtools.h))
$(eval $(call add_include_file,kernel/modtools.h))
$(eval $(call add_include_file,kernel/macc.h))
$(eval $(call add_include_file,kernel/utils.h))
$(eval $(call add_include_file,kernel/satgen.h))
$(eval $(call add_include_file,libs/ezsat/ezsat.h))
$(eval $(call add_include_file,libs/ezsat/ezminisat.h))
$(eval $(call add_include_file,libs/sha1/sha1.h))
$(eval $(call add_include_file,passes/fsm/fsmdata.h))
$(eval $(call add_include_file,frontends/ast/ast.h))
$(eval $(call add_include_file,backends/ilang/ilang_backend.h))
OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o
OBJS += kernel/cellaigs.o kernel/celledges.o
kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"'
kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"'
OBJS += libs/bigint/BigIntegerAlgorithms.o libs/bigint/BigInteger.o libs/bigint/BigIntegerUtils.o
OBJS += libs/bigint/BigUnsigned.o libs/bigint/BigUnsignedInABase.o
OBJS += libs/sha1/sha1.o
ifneq ($(SMALL),1)
OBJS += libs/subcircuit/subcircuit.o
OBJS += libs/ezsat/ezsat.o
OBJS += libs/ezsat/ezminisat.o
OBJS += libs/minisat/Options.o
OBJS += libs/minisat/SimpSolver.o
OBJS += libs/minisat/Solver.o
OBJS += libs/minisat/System.o
include $(YOSYS_SRC)/frontends/*/Makefile.inc
include $(YOSYS_SRC)/passes/*/Makefile.inc
include $(YOSYS_SRC)/backends/*/Makefile.inc
include $(YOSYS_SRC)/techlibs/*/Makefile.inc
else
include frontends/verilog/Makefile.inc
include frontends/ilang/Makefile.inc
include frontends/ast/Makefile.inc
include frontends/blif/Makefile.inc
OBJS += passes/hierarchy/hierarchy.o
OBJS += passes/cmds/select.o
OBJS += passes/cmds/show.o
OBJS += passes/cmds/stat.o
OBJS += passes/cmds/cover.o
OBJS += passes/cmds/design.o
OBJS += passes/cmds/plugin.o
include passes/proc/Makefile.inc
include passes/opt/Makefile.inc
include passes/techmap/Makefile.inc
include backends/verilog/Makefile.inc
include backends/ilang/Makefile.inc
include techlibs/common/Makefile.inc
endif
top-all: $(TARGETS) $(EXTRA_TARGETS)
@echo ""
@echo " Build successful."
@echo ""
ifeq ($(CONFIG),emcc)
yosys.js: $(filter-out yosysjs-$(YOSYS_VER).zip,$(EXTRA_TARGETS))
endif
yosys$(EXE): $(OBJS)
$(P) $(LD) -o yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS)
libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
$(P) $(LD) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LDFLAGS) $^ $(LDLIBS)
%.o: %.cc
$(Q) mkdir -p $(dir $@)
$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $<
%.o: %.cpp
$(Q) mkdir -p $(dir $@)
$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $<
YOSYS_VER_STR := Yosys $(YOSYS_VER) (git sha1 $(GIT_REV), $(notdir $(CXX)) $(shell \
$(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1) $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)))
kernel/version_$(GIT_REV).cc: $(YOSYS_SRC)/Makefile
$(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc
$(Q) mkdir -p kernel && echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"$(YOSYS_VER_STR)\"; }" > kernel/version_$(GIT_REV).cc
yosys-config: misc/yosys-config.in
$(P) $(SED) -e 's#@CXXFLAGS@#$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(CXXFLAGS))#;' \
-e 's#@CXX@#$(CXX)#;' -e 's#@LDFLAGS@#$(LDFLAGS)#;' -e 's#@LDLIBS@#$(LDLIBS)#;' \
-e 's#@BINDIR@#$(BINDIR)#;' -e 's#@DATDIR@#$(DATDIR)#;' < $< > yosys-config
$(Q) chmod +x yosys-config
abc/abc-$(ABCREV)$(EXE) abc/libabc-$(ABCREV).a:
$(P)
ifneq ($(ABCREV),default)
$(Q) if ( cd abc 2> /dev/null && hg identify; ) | grep -q +; then \
echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \
fi
$(Q) if test "`cd abc 2> /dev/null && hg identify | cut -f1 -d' '`" != "$(ABCREV)"; then \
test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \
echo "Pulling ABC from $(ABCURL):"; set -x; \
test -d abc || git clone $(ABCURL) abc; \
cd abc && $(MAKE) DEP= clean && git fetch origin master && git checkout $(ABCREV); \
fi
endif
$(Q) rm -f abc/abc-[0-9a-f]*
$(Q) cd abc && $(MAKE) $(S) $(ABCMKARGS) $(if $(filter %.a,$@),PROG="abc-$(ABCREV)",PROG="abc-$(ABCREV)$(EXE)") MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: " $(if $(filter %.a,$@),libabc-$(ABCREV).a)
ifeq ($(ABCREV),default)
.PHONY: abc/abc-$(ABCREV)$(EXE)
.PHONY: abc/libabc-$(ABCREV).a
endif
yosys-abc$(EXE): abc/abc-$(ABCREV)$(EXE)
$(P) cp abc/abc-$(ABCREV)$(EXE) yosys-abc$(EXE)
ifneq ($(SEED),)
SEEDOPT="-S $(SEED)"
else
SEEDOPT=""
endif
test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/simple && bash run-test.sh $(SEEDOPT)
+cd tests/hana && bash run-test.sh $(SEEDOPT)
+cd tests/asicworld && bash run-test.sh $(SEEDOPT)
+cd tests/realmath && bash run-test.sh $(SEEDOPT)
+cd tests/share && bash run-test.sh $(SEEDOPT)
+cd tests/fsm && bash run-test.sh $(SEEDOPT)
+cd tests/techmap && bash run-test.sh
+cd tests/memories && bash run-test.sh $(SEEDOPT)
+cd tests/bram && bash run-test.sh $(SEEDOPT)
+cd tests/various && bash run-test.sh
+cd tests/sat && bash run-test.sh
@echo ""
@echo " Passed \"make test\"."
@echo ""
VALGRIND ?= valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all
vgtest: $(TARGETS) $(EXTRA_TARGETS)
$(VALGRIND) ./yosys -p 'setattr -mod -unset top; synth' $$( ls tests/simple/*.v | grep -v repwhile.v )
@echo ""
@echo " Passed \"make vgtest\"."
@echo ""
vloghtb: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/vloghtb && bash run-test.sh
@echo ""
@echo " Passed \"make vloghtb\"."
@echo ""
install: $(TARGETS) $(EXTRA_TARGETS)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
$(INSTALL_SUDO) install $(TARGETS) $(DESTDIR)$(BINDIR)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)
$(INSTALL_SUDO) ldconfig
endif
uninstall:
$(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)$(BINDIR),$(notdir $(TARGETS)))
$(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR)
ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so
endif
update-manual: $(TARGETS) $(EXTRA_TARGETS)
cd manual && ../yosys -p 'help -write-tex-command-reference-manual'
manual: $(TARGETS) $(EXTRA_TARGETS)
cd manual && bash appnotes.sh
cd manual && bash presentation.sh
cd manual && bash manual.sh
clean:
rm -rf share
if test -d manual; then cd manual && sh clean.sh; fi
rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS)
rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]*
rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d
clean-abc:
$(MAKE) -C abc DEP= clean
rm -f yosys-abc$(EXE) abc/abc-[0-9a-f]*
mrproper: clean
git clean -xdf
qtcreator:
{ for file in $(basename $(OBJS)); do \
for prefix in cc y l; do if [ -f $${file}.$${prefix} ]; then echo $$file.$${prefix}; fi; done \
done; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \); } > qtcreator.files
{ echo .; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \) -printf '%h\n' | sort -u; } > qtcreator.includes
touch qtcreator.config qtcreator.creator
vcxsrc: $(GENFILES) $(EXTRA_TARGETS)
rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip}
set -e; for f in `ls $(filter %.cc %.cpp,$(GENFILES)) $(addsuffix .cc,$(basename $(OBJS))) $(addsuffix .cpp,$(basename $(OBJS))) 2> /dev/null`; do \
echo "Analyse: $$f" >&2; cpp -std=c++11 -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt
bash misc/create_vcxsrc.sh yosys-win32-vcxsrc $(YOSYS_VER) $(GIT_REV)
echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys (Version Information Unavailable)\"; }" > kernel/version.cc
zip yosys-win32-vcxsrc-$(YOSYS_VER)/genfiles.zip $(GENFILES) kernel/version.cc
zip -r yosys-win32-vcxsrc-$(YOSYS_VER).zip yosys-win32-vcxsrc-$(YOSYS_VER)/
rm -f srcfiles.txt kernel/version.cc
ifeq ($(CONFIG),mxe)
mxebin: $(TARGETS) $(EXTRA_TARGETS)
rm -rf yosys-win32-mxebin-$(YOSYS_VER){,.zip}
mkdir -p yosys-win32-mxebin-$(YOSYS_VER)
cp -r yosys.exe share/ yosys-win32-mxebin-$(YOSYS_VER)/
ifeq ($(ENABLE_ABC),1)
cp -r yosys-abc.exe abc/lib/x86/pthreadVC2.dll yosys-win32-mxebin-$(YOSYS_VER)/
endif
echo -en 'This is Yosys $(YOSYS_VER) for Win32.\r\n' > yosys-win32-mxebin-$(YOSYS_VER)/readme.txt
echo -en 'Documentation at http://www.clifford.at/yosys/.\r\n' >> yosys-win32-mxebin-$(YOSYS_VER)/readme.txt
zip -r yosys-win32-mxebin-$(YOSYS_VER).zip yosys-win32-mxebin-$(YOSYS_VER)/
endif
config-clean: clean
rm -f Makefile.conf
config-clang: clean
echo 'CONFIG := clang' > Makefile.conf
config-gcc: clean
echo 'CONFIG := gcc' > Makefile.conf
config-gcc-4.8: clean
echo 'CONFIG := gcc-4.8' > Makefile.conf
config-emcc: clean
echo 'CONFIG := emcc' > Makefile.conf
echo 'ENABLE_TCL := 0' >> Makefile.conf
echo 'ENABLE_ABC := 0' >> Makefile.conf
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
echo 'ENABLE_READLINE := 0' >> Makefile.conf
config-mxe: clean
echo 'CONFIG := mxe' > Makefile.conf
echo 'ENABLE_TCL := 0' >> Makefile.conf
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
echo 'ENABLE_READLINE := 0' >> Makefile.conf
config-msys2: clean
echo 'CONFIG := msys2' > Makefile.conf
config-gprof: clean
echo 'CONFIG := gcc' > Makefile.conf
echo 'ENABLE_GPROF := 1' >> Makefile.conf
config-sudo:
echo "INSTALL_SUDO := sudo" >> Makefile.conf
echo-yosys-ver:
@echo "$(YOSYS_VER)"
echo-git-rev:
@echo "$(GIT_REV)"
-include libs/*/*.d
-include frontends/*/*.d
-include passes/*/*.d
-include backends/*/*.d
-include kernel/*.d
-include techlibs/*/*.d
.PHONY: all top-all abc test install install-abc manual clean mrproper qtcreator
.PHONY: config-clean config-clang config-gcc config-gcc-4.8 config-gprof config-sudo

451
yosys/README Normal file
View File

@ -0,0 +1,451 @@
/-----------------------------------------------------------------------------\
| |
| yosys -- Yosys Open SYnthesis Suite |
| |
| Copyright (C) 2012 - 2016 Clifford Wolf <clifford@clifford.at> |
| |
| Permission to use, copy, modify, and/or distribute this software for any |
| purpose with or without fee is hereby granted, provided that the above |
| copyright notice and this permission notice appear in all copies. |
| |
| THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| |
\-----------------------------------------------------------------------------/
yosys -- Yosys Open SYnthesis Suite
===================================
This is a framework for RTL synthesis tools. It currently has
extensive Verilog-2005 support and provides a basic set of
synthesis algorithms for various application domains.
Yosys can be adapted to perform any synthesis job by combining
the existing passes (algorithms) using synthesis scripts and
adding additional passes as needed by extending the yosys C++
code base.
Yosys is free software licensed under the ISC license (a GPL
compatible license that is similar in terms to the MIT license
or the 2-clause BSD license).
Web Site
========
More information and documentation can be found on the Yosys web site:
http://www.clifford.at/yosys/
Getting Started
===============
You need a C++ compiler with C++11 support (up-to-date CLANG or GCC is
recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make.
TCL, readline and libffi are optional (see ENABLE_* settings in Makefile).
Xdot (graphviz) is used by the "show" command in yosys to display schematics.
For example on Ubuntu Linux 16.04 LTS the following commands will install all
prerequisites for building yosys:
$ sudo apt-get install build-essential clang bison flex \
libreadline-dev gawk tcl-dev libffi-dev git mercurial \
graphviz xdot pkg-config python3
There are also pre-compiled Yosys binary packages for Ubuntu and Win32 as well
as a source distribution for Visual Studio. Visit the Yosys download page for
more information:
http://www.clifford.at/yosys/download.html
To configure the build system to use a specific compiler, use one of
$ make config-clang
$ make config-gcc
For other compilers and build configurations it might be
necessary to make some changes to the config section of the
Makefile.
$ vi Makefile ..or..
$ vi Makefile.conf
To build Yosys simply type 'make' in this directory.
$ make
$ make test
$ sudo make install
Note that this also downloads, builds and installs ABC (using yosys-abc
as executable name).
Yosys can be used with the interactive command shell, with
synthesis scripts or with command line arguments. Let's perform
a simple synthesis job using the interactive command shell:
$ ./yosys
yosys>
the command "help" can be used to print a list of all available
commands and "help <command>" to print details on the specified command:
yosys> help help
reading the design using the Verilog frontend:
yosys> read_verilog tests/simple/fiedler-cooley.v
writing the design to the console in yosys's internal format:
yosys> write_ilang
elaborate design hierarchy:
yosys> hierarchy
convert processes ("always" blocks) to netlist elements and perform
some simple optimizations:
yosys> proc; opt
display design netlist using xdot:
yosys> show
the same thing using 'gv' as postscript viewer:
yosys> show -format ps -viewer gv
translating netlist to gate logic and perform some simple optimizations:
yosys> techmap; opt
write design netlist to a new Verilog file:
yosys> write_verilog synth.v
a similar synthesis can be performed using yosys command line options only:
$ ./yosys -o synth.v -p hierarchy -p proc -p opt \
-p techmap -p opt tests/simple/fiedler-cooley.v
or using a simple synthesis script:
$ cat synth.ys
read_verilog tests/simple/fiedler-cooley.v
hierarchy; proc; opt; techmap; opt
write_verilog synth.v
$ ./yosys synth.ys
It is also possible to only have the synthesis commands but not the read/write
commands in the synthesis script:
$ cat synth.ys
hierarchy; proc; opt; techmap; opt
$ ./yosys -o synth.v tests/simple/fiedler-cooley.v synth.ys
The following very basic synthesis script should work well with all designs:
# check design hierarchy
hierarchy
# translate processes (always blocks)
proc; opt
# detect and optimize FSM encodings
fsm; opt
# implement memories (arrays)
memory; opt
# convert to gate logic
techmap; opt
If ABC is enabled in the Yosys build configuration and a cell library is given
in the liberty file mycells.lib, the following synthesis script will synthesize
for the given cell library:
# the high-level stuff
hierarchy; proc; fsm; opt; memory; opt
# mapping to internal cell library
techmap; opt
# mapping flip-flops to mycells.lib
dfflibmap -liberty mycells.lib
# mapping logic to mycells.lib
abc -liberty mycells.lib
# cleanup
clean
If you do not have a liberty file but want to test this synthesis script,
you can use the file examples/cmos/cmos_cells.lib from the yosys sources.
Liberty file downloads for and information about free and open ASIC standard
cell libraries can be found here:
http://www.vlsitechnology.org/html/libraries.html
http://www.vlsitechnology.org/synopsys/vsclib013.lib
The command "synth" provides a good default synthesis script (see "help synth").
If possible a synthesis script should borrow from "synth". For example:
# the high-level stuff
hierarchy
synth -run coarse
# mapping to internal cells
techmap; opt -fast
dfflibmap -liberty mycells.lib
abc -liberty mycells.lib
clean
Yosys is under construction. A more detailed documentation will follow.
Unsupported Verilog-2005 Features
=================================
The following Verilog-2005 features are not supported by
yosys and there are currently no plans to add support
for them:
- Non-synthesizable language features as defined in
IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002
- The "tri", "triand", "trior", "wand" and "wor" net types
- The "config" keyword and library map files
- The "disable", "primitive" and "specify" statements
- Latched logic (is synthesized as logic with feedback loops)
Verilog Attributes and non-standard features
============================================
- The 'full_case' attribute on case statements is supported
(also the non-standard "// synopsys full_case" directive)
- The 'parallel_case' attribute on case statements is supported
(also the non-standard "// synopsys parallel_case" directive)
- The "// synopsys translate_off" and "// synopsys translate_on"
directives are also supported (but the use of `ifdef .. `endif
is strongly recommended instead).
- The "nomem2reg" attribute on modules or arrays prohibits the
automatic early conversion of arrays to separate registers. This
is potentially dangerous. Usually the front-end has good reasons
for converting an array to a list of registers. Prohibiting this
step will likely result in incorrect synthesis results.
- The "mem2reg" attribute on modules or arrays forces the early
conversion of arrays to separate registers.
- The "nomeminit" attribute on modules or arrays prohibits the
creation of initialized memories. This effectively puts "mem2reg"
on all memories that are written to in an "initial" block and
are not ROMs.
- The "nolatches" attribute on modules or always-blocks
prohibits the generation of logic-loops for latches. Instead
all not explicitly assigned values default to x-bits. This does
not affect clocked storage elements such as flip-flops.
- The "nosync" attribute on registers prohibits the generation of a
storage element. The register itself will always have all bits set
to 'x' (undefined). The variable may only be used as blocking assigned
temporary variable within an always block. This is mostly used internally
by yosys to synthesize Verilog functions and access arrays.
- The "onehot" attribute on wires mark them as onehot state register. This
is used for example for memory port sharing and set by the fsm_map pass.
- The "blackbox" attribute on modules is used to mark empty stub modules
that have the same ports as the real thing but do not contain information
on the internal configuration. This modules are only used by the synthesis
passes to identify input and output ports of cells. The Verilog backend
also does not output blackbox modules on default.
- The "keep" attribute on cells and wires is used to mark objects that should
never be removed by the optimizer. This is used for example for cells that
have hidden connections that are not part of the netlist, such as IO pads.
Setting the "keep" attribute on a module has the same effect as setting it
on all instances of the module.
- The "keep_hierarchy" attribute on cells and modules keeps the "flatten"
command from flattening the indicated cells and modules.
- The "init" attribute on wires is set by the frontend when a register is
initialized "FPGA-style" with 'reg foo = val'. It can be used during synthesis
to add the necessary reset logic.
- The "top" attribute on a module marks this module as the top of the
design hierarchy. The "hierarchy" command sets this attribute when called
with "-top". Other commands, such as "flatten" and various backends
use this attribute to determine the top module.
- The "src" attribute is set on cells and wires created by to the string
"<hdl-file-name>:<line-number>" by the HDL front-end and is then carried
through the synthesis. When entities are combined, a new |-separated
string is created that contains all the string from the original entities.
- In addition to the (* ... *) attribute syntax, yosys supports
the non-standard {* ... *} attribute syntax to set default attributes
for everything that comes after the {* ... *} statement. (Reset
by adding an empty {* *} statement.)
- In module parameter and port declarations, and cell port and parameter
lists, a trailing comma is ignored. This simplifies writing verilog code
generators a bit in some cases.
- Modules can be declared with "module mod_name(...);" (with three dots
instead of a list of module ports). With this syntax it is sufficient
to simply declare a module port as 'input' or 'output' in the module
body.
- When defining a macro with `define, all text between triple double quotes
is interpreted as macro body, even if it contains unescaped newlines. The
tipple double quotes are removed from the macro body. For example:
`define MY_MACRO(a, b) """
assign a = 23;
assign b = 42;
"""
- The attribute "via_celltype" can be used to implement a Verilog task or
function by instantiating the specified cell type. The value is the name
of the cell type to use. For functions the name of the output port can
be specified by appending it to the cell type separated by a whitespace.
The body of the task or function is unused in this case and can be used
to specify a behavioral model of the cell type for simulation. For example:
module my_add3(A, B, C, Y);
parameter WIDTH = 8;
input [WIDTH-1:0] A, B, C;
output [WIDTH-1:0] Y;
...
endmodule
module top;
...
(* via_celltype = "my_add3 Y" *)
(* via_celltype_defparam_WIDTH = 32 *)
function [31:0] add3;
input [31:0] A, B, C;
begin
add3 = A + B + C;
end
endfunction
...
endmodule
- A limited subset of DPI-C functions is supported. The plugin mechanism
(see "help plugin") can be used to load .so files with implementations
of DPI-C routines. As a non-standard extension it is possible to specify
a plugin alias using the "<alias>:" syntax. for example:
module dpitest;
import "DPI-C" function foo:round = real my_round (real);
parameter real r = my_round(12.345);
endmodule
$ yosys -p 'plugin -a foo -i /lib/libm.so; read_verilog dpitest.v'
- Sized constants (the syntax <size>'s?[bodh]<value>) support constant
expressions as <size>. If the expression is not a simple identifier, it
must be put in parentheses. Examples: WIDTH'd42, (4+2)'b101010
- The system tasks $finish and $display are supported in initial blocks
in an unconditional context (only if/case statements on parameters
and constant values). The intended use for this is synthesis-time DRC.
Non-standard or SystemVerilog features for formal verification
==============================================================
- Support for "assert", "assume", and "restrict" is enabled when
read_verilog is called with -formal.
- The system task $initstate evaluates to 1 in the initial state and
to 0 otherwise.
- The system task $anyconst evaluates to any constant value.
- The system task $anyseq evaluates to any value, possibly a different
value in each cycle.
- The SystemVerilog tasks $past, $stable, $rose and $fell are supported
in any clocked block.
- The syntax @($global_clock) can be used to create FFs that have no
explicit clock input ($ff cells).
Supported features from SystemVerilog
=====================================
When read_verilog is called with -sv, it accepts some language features
from SystemVerilog:
- The "assert" statement from SystemVerilog is supported in its most basic
form. In module context: "assert property (<expression>);" and within an
always block: "assert(<expression>);". It is transformed to a $assert cell.
- The "assume" and "restrict" statements from SystemVerilog are also
supported. The same limitations as with the "assert" statement apply.
- The keywords "always_comb", "always_ff" and "always_latch", "logic" and
"bit" are supported.
- SystemVerilog packages are supported. Once a SystemVerilog file is read
into a design with "read_verilog", all its packages are available to
SystemVerilog files being read into the same design afterwards.
Building the documentation
==========================
Note that there is no need to build the manual if you just want to read it.
Simply download the PDF from http://www.clifford.at/yosys/documentation.html
instead.
On Ubuntu, texlive needs these packages to be able to build the manual:
sudo apt-get install texlive-binaries
sudo apt-get install texlive-science # install algorithm2e.sty
sudo apt-get install texlive-bibtex-extra # gets multibib.sty
sudo apt-get install texlive-fonts-extra # gets skull.sty and dsfont.sty
sudo apt-get install texlive-publishers # IEEEtran.cls
Also the non-free font luximono should be installed, there is unfortunately
no Ubuntu package for this so it should be installed separately using
`getnonfreefonts`:
wget https://tug.org/fonts/getnonfreefonts/install-getnonfreefonts
sudo texlua install-getnonfreefonts # will install to /usr/local by default, can be changed by editing BINDIR at MANDIR at the top of the script
getnonfreefonts luximono # installs to /home/user/texmf
Then execute, from the root of the repository:
make manual
Notes:
- To run `make manual` you need to have installed yosys with `make install`,
otherwise it will fail on finding `kernel/yosys.h` while building
`PRESENTATION_Prog`.

View File

@ -0,0 +1,3 @@
OBJS += backends/blif/blif.o

632
yosys/backends/blif/blif.cc Normal file
View File

@ -0,0 +1,632 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
// [[CITE]] Berkeley Logic Interchange Format (BLIF)
// University of California. Berkeley. July 28, 1992
// http://www.ece.cmu.edu/~ee760/760docs/blif.pdf
#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct BlifDumperConfig
{
bool icells_mode;
bool conn_mode;
bool impltf_mode;
bool gates_mode;
bool cname_mode;
bool param_mode;
bool attr_mode;
bool blackbox_mode;
bool noalias_mode;
std::string buf_type, buf_in, buf_out;
std::map<RTLIL::IdString, std::pair<RTLIL::IdString, RTLIL::IdString>> unbuf_types;
std::string true_type, true_out, false_type, false_out, undef_type, undef_out;
BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false),
cname_mode(false), param_mode(false), attr_mode(false), blackbox_mode(false), noalias_mode(false) { }
};
struct BlifDumper
{
std::ostream &f;
RTLIL::Module *module;
RTLIL::Design *design;
BlifDumperConfig *config;
CellTypes ct;
SigMap sigmap;
dict<SigBit, int> init_bits;
BlifDumper(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BlifDumperConfig *config) :
f(f), module(module), design(design), config(config), ct(design), sigmap(module)
{
for (Wire *wire : module->wires())
if (wire->attributes.count("\\init")) {
SigSpec initsig = sigmap(wire);
Const initval = wire->attributes.at("\\init");
for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++)
switch (initval[i]) {
case State::S0:
init_bits[initsig[i]] = 0;
break;
case State::S1:
init_bits[initsig[i]] = 1;
break;
default:
break;
}
}
}
vector<shared_str> cstr_buf;
pool<SigBit> cstr_bits_seen;
const char *cstr(RTLIL::IdString id)
{
std::string str = RTLIL::unescape_id(id);
for (size_t i = 0; i < str.size(); i++)
if (str[i] == '#' || str[i] == '=' || str[i] == '<' || str[i] == '>')
str[i] = '?';
cstr_buf.push_back(str);
return cstr_buf.back().c_str();
}
const char *cstr(RTLIL::SigBit sig)
{
cstr_bits_seen.insert(sig);
if (sig.wire == NULL) {
if (sig == RTLIL::State::S0) return config->false_type == "-" || config->false_type == "+" ? config->false_out.c_str() : "$false";
if (sig == RTLIL::State::S1) return config->true_type == "-" || config->true_type == "+" ? config->true_out.c_str() : "$true";
return config->undef_type == "-" || config->undef_type == "+" ? config->undef_out.c_str() : "$undef";
}
std::string str = RTLIL::unescape_id(sig.wire->name);
for (size_t i = 0; i < str.size(); i++)
if (str[i] == '#' || str[i] == '=' || str[i] == '<' || str[i] == '>')
str[i] = '?';
if (sig.wire->width != 1)
str += stringf("[%d]", sig.offset);
cstr_buf.push_back(str);
return cstr_buf.back().c_str();
}
const char *cstr_init(RTLIL::SigBit sig)
{
sigmap.apply(sig);
if (init_bits.count(sig) == 0)
return " 2";
string str = stringf(" %d", init_bits.at(sig));
cstr_buf.push_back(str);
return cstr_buf.back().c_str();
}
const char *subckt_or_gate(std::string cell_type)
{
if (!config->gates_mode)
return "subckt";
if (!design->modules_.count(RTLIL::escape_id(cell_type)))
return "gate";
if (design->modules_.at(RTLIL::escape_id(cell_type))->get_bool_attribute("\\blackbox"))
return "gate";
return "subckt";
}
void dump_params(const char *command, dict<IdString, Const> &params)
{
for (auto &param : params) {
f << stringf("%s %s ", command, RTLIL::id2cstr(param.first));
if (param.second.flags & RTLIL::CONST_FLAG_STRING) {
std::string str = param.second.decode_string();
f << stringf("\"");
for (char ch : str)
if (ch == '"' || ch == '\\')
f << stringf("\\%c", ch);
else if (ch < 32 || ch >= 127)
f << stringf("\\%03o", ch);
else
f << stringf("%c", ch);
f << stringf("\"\n");
} else
f << stringf("%s\n", param.second.as_string().c_str());
}
}
void dump()
{
f << stringf("\n");
f << stringf(".model %s\n", cstr(module->name));
std::map<int, RTLIL::Wire*> inputs, outputs;
for (auto &wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_input)
inputs[wire->port_id] = wire;
if (wire->port_output)
outputs[wire->port_id] = wire;
}
f << stringf(".inputs");
for (auto &it : inputs) {
RTLIL::Wire *wire = it.second;
for (int i = 0; i < wire->width; i++)
f << stringf(" %s", cstr(RTLIL::SigSpec(wire, i)));
}
f << stringf("\n");
f << stringf(".outputs");
for (auto &it : outputs) {
RTLIL::Wire *wire = it.second;
for (int i = 0; i < wire->width; i++)
f << stringf(" %s", cstr(RTLIL::SigSpec(wire, i)));
}
f << stringf("\n");
if (module->get_bool_attribute("\\blackbox")) {
f << stringf(".blackbox\n");
f << stringf(".end\n");
return;
}
if (!config->impltf_mode) {
if (!config->false_type.empty()) {
if (config->false_type == "+")
f << stringf(".names %s\n", config->false_out.c_str());
else if (config->false_type != "-")
f << stringf(".%s %s %s=$false\n", subckt_or_gate(config->false_type),
config->false_type.c_str(), config->false_out.c_str());
} else
f << stringf(".names $false\n");
if (!config->true_type.empty()) {
if (config->true_type == "+")
f << stringf(".names %s\n1\n", config->true_out.c_str());
else if (config->true_type != "-")
f << stringf(".%s %s %s=$true\n", subckt_or_gate(config->true_type),
config->true_type.c_str(), config->true_out.c_str());
} else
f << stringf(".names $true\n1\n");
if (!config->undef_type.empty()) {
if (config->undef_type == "+")
f << stringf(".names %s\n", config->undef_out.c_str());
else if (config->undef_type != "-")
f << stringf(".%s %s %s=$undef\n", subckt_or_gate(config->undef_type),
config->undef_type.c_str(), config->undef_out.c_str());
} else
f << stringf(".names $undef\n");
}
for (auto &cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
if (config->unbuf_types.count(cell->type)) {
auto portnames = config->unbuf_types.at(cell->type);
f << stringf(".names %s %s\n1 1\n",
cstr(cell->getPort(portnames.first)), cstr(cell->getPort(portnames.second)));
continue;
}
if (!config->icells_mode && cell->type == "$_NOT_") {
f << stringf(".names %s %s\n0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->icells_mode && cell->type == "$_AND_") {
f << stringf(".names %s %s %s\n11 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->icells_mode && cell->type == "$_OR_") {
f << stringf(".names %s %s %s\n1- 1\n-1 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->icells_mode && cell->type == "$_XOR_") {
f << stringf(".names %s %s %s\n10 1\n01 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->icells_mode && cell->type == "$_NAND_") {
f << stringf(".names %s %s %s\n0- 1\n-0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->icells_mode && cell->type == "$_NOR_") {
f << stringf(".names %s %s %s\n00 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->icells_mode && cell->type == "$_XNOR_") {
f << stringf(".names %s %s %s\n11 1\n00 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->icells_mode && cell->type == "$_AOI3_") {
f << stringf(".names %s %s %s %s\n-00 1\n0-0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\C")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->icells_mode && cell->type == "$_OAI3_") {
f << stringf(".names %s %s %s %s\n00- 1\n--0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\C")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->icells_mode && cell->type == "$_AOI4_") {
f << stringf(".names %s %s %s %s %s\n-0-0 1\n-00- 1\n0--0 1\n0-0- 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")),
cstr(cell->getPort("\\C")), cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->icells_mode && cell->type == "$_OAI4_") {
f << stringf(".names %s %s %s %s %s\n00-- 1\n--00 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")),
cstr(cell->getPort("\\C")), cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->icells_mode && cell->type == "$_MUX_") {
f << stringf(".names %s %s %s %s\n1-0 1\n-11 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")),
cstr(cell->getPort("\\S")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->icells_mode && cell->type == "$_FF_") {
f << stringf(".latch %s %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr_init(cell->getPort("\\Q")));
continue;
}
if (!config->icells_mode && cell->type == "$_DFF_N_") {
f << stringf(".latch %s %s fe %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr(cell->getPort("\\C")), cstr_init(cell->getPort("\\Q")));
continue;
}
if (!config->icells_mode && cell->type == "$_DFF_P_") {
f << stringf(".latch %s %s re %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr(cell->getPort("\\C")), cstr_init(cell->getPort("\\Q")));
continue;
}
if (!config->icells_mode && cell->type == "$_DLATCH_N_") {
f << stringf(".latch %s %s al %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr(cell->getPort("\\E")), cstr_init(cell->getPort("\\Q")));
continue;
}
if (!config->icells_mode && cell->type == "$_DLATCH_P_") {
f << stringf(".latch %s %s ah %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr(cell->getPort("\\E")), cstr_init(cell->getPort("\\Q")));
continue;
}
if (!config->icells_mode && cell->type == "$lut") {
f << stringf(".names");
auto &inputs = cell->getPort("\\A");
auto width = cell->parameters.at("\\WIDTH").as_int();
log_assert(inputs.size() == width);
for (int i = width-1; i >= 0; i--)
f << stringf(" %s", cstr(inputs.extract(i, 1)));
auto &output = cell->getPort("\\Y");
log_assert(output.size() == 1);
f << stringf(" %s", cstr(output));
f << stringf("\n");
RTLIL::SigSpec mask = cell->parameters.at("\\LUT");
for (int i = 0; i < (1 << width); i++)
if (mask[i] == RTLIL::S1) {
for (int j = width-1; j >= 0; j--) {
f << ((i>>j)&1 ? '1' : '0');
}
f << " 1\n";
}
continue;
}
if (!config->icells_mode && cell->type == "$sop") {
f << stringf(".names");
auto &inputs = cell->getPort("\\A");
auto width = cell->parameters.at("\\WIDTH").as_int();
auto depth = cell->parameters.at("\\DEPTH").as_int();
vector<State> table = cell->parameters.at("\\TABLE").bits;
while (GetSize(table) < 2*width*depth)
table.push_back(State::S0);
log_assert(inputs.size() == width);
for (int i = 0; i < width; i++)
f << stringf(" %s", cstr(inputs.extract(i, 1)));
auto &output = cell->getPort("\\Y");
log_assert(output.size() == 1);
f << stringf(" %s", cstr(output));
f << stringf("\n");
for (int i = 0; i < depth; i++) {
for (int j = 0; j < width; j++) {
bool pat0 = table.at(2*width*i + 2*j + 0) == State::S1;
bool pat1 = table.at(2*width*i + 2*j + 1) == State::S1;
if (pat0 && !pat1) f << "0";
else if (!pat0 && pat1) f << "1";
else f << "-";
}
f << " 1\n";
}
continue;
}
f << stringf(".%s %s", subckt_or_gate(cell->type.str()), cstr(cell->type));
for (auto &conn : cell->connections())
for (int i = 0; i < conn.second.size(); i++) {
if (conn.second.size() == 1)
f << stringf(" %s", cstr(conn.first));
else
f << stringf(" %s[%d]", cstr(conn.first), i);
f << stringf("=%s", cstr(conn.second.extract(i, 1)));
}
f << stringf("\n");
if (config->cname_mode)
f << stringf(".cname %s\n", cstr(cell->name));
if (config->attr_mode)
dump_params(".attr", cell->attributes);
if (config->param_mode)
dump_params(".param", cell->parameters);
}
for (auto &conn : module->connections())
for (int i = 0; i < conn.first.size(); i++)
{
SigBit lhs_bit = conn.first[i];
SigBit rhs_bit = conn.second[i];
if (config->noalias_mode && cstr_bits_seen.count(lhs_bit) == 0)
continue;
if (config->conn_mode)
f << stringf(".conn %s %s\n", cstr(rhs_bit), cstr(lhs_bit));
else if (!config->buf_type.empty())
f << stringf(".%s %s %s=%s %s=%s\n", subckt_or_gate(config->buf_type), config->buf_type.c_str(),
config->buf_in.c_str(), cstr(rhs_bit), config->buf_out.c_str(), cstr(lhs_bit));
else
f << stringf(".names %s %s\n1 1\n", cstr(rhs_bit), cstr(lhs_bit));
}
f << stringf(".end\n");
}
static void dump(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BlifDumperConfig &config)
{
BlifDumper dumper(f, module, design, &config);
dumper.dump();
}
};
struct BlifBackend : public Backend {
BlifBackend() : Backend("blif", "write design to BLIF file") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" write_blif [options] [filename]\n");
log("\n");
log("Write the current design to an BLIF file.\n");
log("\n");
log(" -top top_module\n");
log(" set the specified module as design top module\n");
log("\n");
log(" -buf <cell-type> <in-port> <out-port>\n");
log(" use cells of type <cell-type> with the specified port names for buffers\n");
log("\n");
log(" -unbuf <cell-type> <in-port> <out-port>\n");
log(" replace buffer cells with the specified name and port names with\n");
log(" a .names statement that models a buffer\n");
log("\n");
log(" -true <cell-type> <out-port>\n");
log(" -false <cell-type> <out-port>\n");
log(" -undef <cell-type> <out-port>\n");
log(" use the specified cell types to drive nets that are constant 1, 0, or\n");
log(" undefined. when '-' is used as <cell-type>, then <out-port> specifies\n");
log(" the wire name to be used for the constant signal and no cell driving\n");
log(" that wire is generated. when '+' is used as <cell-type>, then <out-port>\n");
log(" specifies the wire name to be used for the constant signal and a .names\n");
log(" statement is generated to drive the wire.\n");
log("\n");
log(" -noalias\n");
log(" if a net name is aliasing another net name, then by default a net\n");
log(" without fanout is created that is driven by the other net. This option\n");
log(" suppresses the generation of this nets without fanout.\n");
log("\n");
log("The following options can be useful when the generated file is not going to be\n");
log("read by a BLIF parser but a custom tool. It is recommended to not name the output\n");
log("file *.blif when any of this options is used.\n");
log("\n");
log(" -icells\n");
log(" do not translate Yosys's internal gates to generic BLIF logic\n");
log(" functions. Instead create .subckt or .gate lines for all cells.\n");
log("\n");
log(" -gates\n");
log(" print .gate instead of .subckt lines for all cells that are not\n");
log(" instantiations of other modules from this design.\n");
log("\n");
log(" -conn\n");
log(" do not generate buffers for connected wires. instead use the\n");
log(" non-standard .conn statement.\n");
log("\n");
log(" -attr\n");
log(" use the non-standard .attr statement to write cell attributes\n");
log("\n");
log(" -param\n");
log(" use the non-standard .param statement to write cell parameters\n");
log("\n");
log(" -cname\n");
log(" use the non-standard .cname statement to write cell names\n");
log("\n");
log(" -blackbox\n");
log(" write blackbox cells with .blackbox statement.\n");
log("\n");
log(" -impltf\n");
log(" do not write definitions for the $true, $false and $undef wires.\n");
log("\n");
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
std::string top_module_name;
std::string buf_type, buf_in, buf_out;
std::string true_type, true_out;
std::string false_type, false_out;
BlifDumperConfig config;
log_header(design, "Executing BLIF backend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-top" && argidx+1 < args.size()) {
top_module_name = args[++argidx];
continue;
}
if (args[argidx] == "-buf" && argidx+3 < args.size()) {
config.buf_type = args[++argidx];
config.buf_in = args[++argidx];
config.buf_out = args[++argidx];
continue;
}
if (args[argidx] == "-unbuf" && argidx+3 < args.size()) {
RTLIL::IdString unbuf_type = RTLIL::escape_id(args[++argidx]);
RTLIL::IdString unbuf_in = RTLIL::escape_id(args[++argidx]);
RTLIL::IdString unbuf_out = RTLIL::escape_id(args[++argidx]);
config.unbuf_types[unbuf_type] = std::pair<RTLIL::IdString, RTLIL::IdString>(unbuf_in, unbuf_out);
continue;
}
if (args[argidx] == "-true" && argidx+2 < args.size()) {
config.true_type = args[++argidx];
config.true_out = args[++argidx];
continue;
}
if (args[argidx] == "-false" && argidx+2 < args.size()) {
config.false_type = args[++argidx];
config.false_out = args[++argidx];
continue;
}
if (args[argidx] == "-undef" && argidx+2 < args.size()) {
config.undef_type = args[++argidx];
config.undef_out = args[++argidx];
continue;
}
if (args[argidx] == "-icells") {
config.icells_mode = true;
continue;
}
if (args[argidx] == "-gates") {
config.gates_mode = true;
continue;
}
if (args[argidx] == "-conn") {
config.conn_mode = true;
continue;
}
if (args[argidx] == "-cname") {
config.cname_mode = true;
continue;
}
if (args[argidx] == "-param") {
config.param_mode = true;
continue;
}
if (args[argidx] == "-attr") {
config.attr_mode = true;
continue;
}
if (args[argidx] == "-blackbox") {
config.blackbox_mode = true;
continue;
}
if (args[argidx] == "-impltf") {
config.impltf_mode = true;
continue;
}
if (args[argidx] == "-noalias") {
config.noalias_mode = true;
continue;
}
break;
}
extra_args(f, filename, args, argidx);
if (top_module_name.empty())
for (auto & mod_it:design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
top_module_name = mod_it.first.str();
*f << stringf("# Generated by %s\n", yosys_version_str);
std::vector<RTLIL::Module*> mod_list;
design->sort();
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox") && !config.blackbox_mode)
continue;
if (module->processes.size() != 0)
log_error("Found unmapped processes in module %s: unmapped processes are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name));
if (module->memories.size() != 0)
log_error("Found unmapped memories in module %s: unmapped memories are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name));
if (module->name == RTLIL::escape_id(top_module_name)) {
BlifDumper::dump(*f, module, design, config);
top_module_name.clear();
continue;
}
mod_list.push_back(module);
}
if (!top_module_name.empty())
log_error("Can't find top module `%s'!\n", top_module_name.c_str());
for (auto module : mod_list)
BlifDumper::dump(*f, module, design, config);
}
} BlifBackend;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,3 @@
OBJS += backends/btor/btor.o

View File

@ -0,0 +1,23 @@
This is the Yosys BTOR backend.
It is developed by Ahmed Irfan <irfan@fbk.eu> - Fondazione Bruno Kessler, Trento, Italy
Master git repository for the BTOR backend:
https://github.com/ahmedirfan1983/yosys
[[CITE]] BTOR: Bit-Precise Modelling of Word-Level Problems for Model Checking
Johannes Kepler University, Linz, Austria
http://fmv.jku.at/papers/BrummayerBiereLonsing-BPR08.pdf
Todos:
------
- Add checks for unsupported stuff
- unsupported cell types
- async resets
- etc..
- Add support for $lut cells

1111
yosys/backends/btor/btor.cc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
#!/bin/sh
#
# Script to write BTOR from Verilog design
#
if [ "$#" -ne 3 ]; then
echo "Usage: $0 input.v output.btor top-module-name" >&2
exit 1
fi
if ! [ -e "$1" ]; then
echo "$1 not found" >&2
exit 1
fi
FULL_PATH=$(readlink -f $1)
DIR=$(dirname $FULL_PATH)
./yosys -q -p "
read_verilog -sv $1;
hierarchy -top $3;
hierarchy -libdir $DIR;
hierarchy -check;
proc;
opt; opt_expr -mux_undef; opt;
rename -hide;;;
#techmap -map +/pmux2mux.v;;
splice; opt;
memory_dff -wr_only;
memory_collect;;
flatten;;
memory_unpack;
splitnets -driver;
setundef -zero -undriven;
opt;;;
write_btor $2;"

View File

@ -0,0 +1,3 @@
OBJS += backends/edif/edif.o

367
yosys/backends/edif/edif.cc Normal file
View File

@ -0,0 +1,367 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
// [[CITE]] EDIF Version 2 0 0 Grammar
// http://web.archive.org/web/20050730021644/http://www.edif.org/documentation/BNF_GRAMMAR/index.html
#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
#define EDIF_DEF(_id) edif_names(RTLIL::unescape_id(_id), true).c_str()
#define EDIF_REF(_id) edif_names(RTLIL::unescape_id(_id), false).c_str()
namespace
{
struct EdifNames
{
int counter;
std::set<std::string> generated_names, used_names;
std::map<std::string, std::string> name_map;
EdifNames() : counter(1) { }
std::string operator()(std::string id, bool define)
{
if (define) {
std::string new_id = operator()(id, false);
return new_id != id ? stringf("(rename %s \"%s\")", new_id.c_str(), id.c_str()) : id;
}
if (name_map.count(id) > 0)
return name_map.at(id);
if (generated_names.count(id) > 0)
goto do_rename;
if (id == "GND" || id == "VCC")
goto do_rename;
for (size_t i = 0; i < id.size(); i++) {
if ('A' <= id[i] && id[i] <= 'Z')
continue;
if ('a' <= id[i] && id[i] <= 'z')
continue;
if ('0' <= id[i] && id[i] <= '9' && i > 0)
continue;
if (id[i] == '_' && i > 0 && i != id.size()-1)
continue;
goto do_rename;
}
used_names.insert(id);
return id;
do_rename:;
std::string gen_name;
while (1) {
gen_name = stringf("id%05d", counter++);
if (generated_names.count(gen_name) == 0 &&
used_names.count(gen_name) == 0)
break;
}
generated_names.insert(gen_name);
name_map[id] = gen_name;
return gen_name;
}
};
}
struct EdifBackend : public Backend {
EdifBackend() : Backend("edif", "write design to EDIF netlist file") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" write_edif [options] [filename]\n");
log("\n");
log("Write the current design to an EDIF netlist file.\n");
log("\n");
log(" -top top_module\n");
log(" set the specified module as design top module\n");
log("\n");
log(" -nogndvcc\n");
log(" do not create \"GND\" and \"VCC\" cells. (this will produce an error\n");
log(" if the design contains constant nets. use \"hilomap\" to map to custom\n");
log(" constant drivers first)\n");
log("\n");
log("Unfortunately there are different \"flavors\" of the EDIF file format. This\n");
log("command generates EDIF files for the Xilinx place&route tools. It might be\n");
log("necessary to make small modifications to this command when a different tool\n");
log("is targeted.\n");
log("\n");
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
log_header(design, "Executing EDIF backend.\n");
std::string top_module_name;
std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
bool nogndvcc = false;
CellTypes ct(design);
EdifNames edif_names;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-top" && argidx+1 < args.size()) {
top_module_name = args[++argidx];
continue;
}
if (args[argidx] == "-nogndvcc") {
nogndvcc = true;
continue;
}
break;
}
extra_args(f, filename, args, argidx);
if (top_module_name.empty())
for (auto & mod_it:design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
top_module_name = mod_it.first.str();
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox"))
continue;
if (top_module_name.empty())
top_module_name = module->name.str();
if (module->processes.size() != 0)
log_error("Found unmapped processes in module %s: unmapped processes are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name));
if (module->memories.size() != 0)
log_error("Found unmapped memories in module %s: unmapped memories are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name));
for (auto cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) {
lib_cell_ports[cell->type];
for (auto p : cell->connections())
lib_cell_ports[cell->type][p.first] = GetSize(p.second);
}
}
}
if (top_module_name.empty())
log_error("No module found in design!\n");
*f << stringf("(edif %s\n", EDIF_DEF(top_module_name));
*f << stringf(" (edifVersion 2 0 0)\n");
*f << stringf(" (edifLevel 0)\n");
*f << stringf(" (keywordMap (keywordLevel 0))\n");
*f << stringf(" (comment \"Generated by %s\")\n", yosys_version_str);
*f << stringf(" (external LIB\n");
*f << stringf(" (edifLevel 0)\n");
*f << stringf(" (technology (numberDefinition))\n");
if (!nogndvcc)
{
*f << stringf(" (cell GND\n");
*f << stringf(" (cellType GENERIC)\n");
*f << stringf(" (view VIEW_NETLIST\n");
*f << stringf(" (viewType NETLIST)\n");
*f << stringf(" (interface (port G (direction OUTPUT)))\n");
*f << stringf(" )\n");
*f << stringf(" )\n");
*f << stringf(" (cell VCC\n");
*f << stringf(" (cellType GENERIC)\n");
*f << stringf(" (view VIEW_NETLIST\n");
*f << stringf(" (viewType NETLIST)\n");
*f << stringf(" (interface (port P (direction OUTPUT)))\n");
*f << stringf(" )\n");
*f << stringf(" )\n");
}
for (auto &cell_it : lib_cell_ports) {
*f << stringf(" (cell %s\n", EDIF_DEF(cell_it.first));
*f << stringf(" (cellType GENERIC)\n");
*f << stringf(" (view VIEW_NETLIST\n");
*f << stringf(" (viewType NETLIST)\n");
*f << stringf(" (interface\n");
for (auto &port_it : cell_it.second) {
const char *dir = "INOUT";
if (ct.cell_known(cell_it.first)) {
if (!ct.cell_output(cell_it.first, port_it.first))
dir = "INPUT";
else if (!ct.cell_input(cell_it.first, port_it.first))
dir = "OUTPUT";
}
if (port_it.second == 1)
*f << stringf(" (port %s (direction %s))\n", EDIF_DEF(port_it.first), dir);
else
*f << stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEF(port_it.first), port_it.second, dir);
}
*f << stringf(" )\n");
*f << stringf(" )\n");
*f << stringf(" )\n");
}
*f << stringf(" )\n");
std::vector<RTLIL::Module*> sorted_modules;
// extract module dependencies
std::map<RTLIL::Module*, std::set<RTLIL::Module*>> module_deps;
for (auto &mod_it : design->modules_) {
module_deps[mod_it.second] = std::set<RTLIL::Module*>();
for (auto &cell_it : mod_it.second->cells_)
if (design->modules_.count(cell_it.second->type) > 0)
module_deps[mod_it.second].insert(design->modules_.at(cell_it.second->type));
}
// simple good-enough topological sort
// (O(n*m) on n elements and depth m)
while (module_deps.size() > 0) {
size_t sorted_modules_idx = sorted_modules.size();
for (auto &it : module_deps) {
for (auto &dep : it.second)
if (module_deps.count(dep) > 0)
goto not_ready_yet;
// log("Next in topological sort: %s\n", RTLIL::id2cstr(it.first->name));
sorted_modules.push_back(it.first);
not_ready_yet:;
}
if (sorted_modules_idx == sorted_modules.size())
log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", RTLIL::id2cstr(module_deps.begin()->first->name));
while (sorted_modules_idx < sorted_modules.size())
module_deps.erase(sorted_modules.at(sorted_modules_idx++));
}
*f << stringf(" (library DESIGN\n");
*f << stringf(" (edifLevel 0)\n");
*f << stringf(" (technology (numberDefinition))\n");
for (auto module : sorted_modules)
{
if (module->get_bool_attribute("\\blackbox"))
continue;
SigMap sigmap(module);
std::map<RTLIL::SigSpec, std::set<std::string>> net_join_db;
*f << stringf(" (cell %s\n", EDIF_DEF(module->name));
*f << stringf(" (cellType GENERIC)\n");
*f << stringf(" (view VIEW_NETLIST\n");
*f << stringf(" (viewType NETLIST)\n");
*f << stringf(" (interface\n");
for (auto &wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_id == 0)
continue;
const char *dir = "INOUT";
if (!wire->port_output)
dir = "INPUT";
else if (!wire->port_input)
dir = "OUTPUT";
if (wire->width == 1) {
*f << stringf(" (port %s (direction %s))\n", EDIF_DEF(wire->name), dir);
RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire));
net_join_db[sig].insert(stringf("(portRef %s)", EDIF_REF(wire->name)));
} else {
*f << stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEF(wire->name), wire->width, dir);
for (int i = 0; i < wire->width; i++) {
RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire, i));
net_join_db[sig].insert(stringf("(portRef (member %s %d))", EDIF_REF(wire->name), i));
}
}
}
*f << stringf(" )\n");
*f << stringf(" (contents\n");
if (!nogndvcc) {
*f << stringf(" (instance GND (viewRef VIEW_NETLIST (cellRef GND (libraryRef LIB))))\n");
*f << stringf(" (instance VCC (viewRef VIEW_NETLIST (cellRef VCC (libraryRef LIB))))\n");
}
for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
*f << stringf(" (instance %s\n", EDIF_DEF(cell->name));
*f << stringf(" (viewRef VIEW_NETLIST (cellRef %s%s))", EDIF_REF(cell->type),
lib_cell_ports.count(cell->type) > 0 ? " (libraryRef LIB)" : "");
for (auto &p : cell->parameters)
if ((p.second.flags & RTLIL::CONST_FLAG_STRING) != 0)
*f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(p.first), p.second.decode_string().c_str());
else if (p.second.bits.size() <= 32 && RTLIL::SigSpec(p.second).is_fully_def())
*f << stringf("\n (property %s (integer %u))", EDIF_DEF(p.first), p.second.as_int());
else {
std::string hex_string = "";
for (size_t i = 0; i < p.second.bits.size(); i += 4) {
int digit_value = 0;
if (i+0 < p.second.bits.size() && p.second.bits.at(i+0) == RTLIL::State::S1) digit_value |= 1;
if (i+1 < p.second.bits.size() && p.second.bits.at(i+1) == RTLIL::State::S1) digit_value |= 2;
if (i+2 < p.second.bits.size() && p.second.bits.at(i+2) == RTLIL::State::S1) digit_value |= 4;
if (i+3 < p.second.bits.size() && p.second.bits.at(i+3) == RTLIL::State::S1) digit_value |= 8;
char digit_str[2] = { "0123456789abcdef"[digit_value], 0 };
hex_string = std::string(digit_str) + hex_string;
}
*f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(p.first), GetSize(p.second.bits), hex_string.c_str());
}
*f << stringf(")\n");
for (auto &p : cell->connections()) {
RTLIL::SigSpec sig = sigmap(p.second);
for (int i = 0; i < GetSize(sig); i++)
if (sig.size() == 1)
net_join_db[sig[i]].insert(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p.first), EDIF_REF(cell->name)));
else
net_join_db[sig[i]].insert(stringf("(portRef (member %s %d) (instanceRef %s))", EDIF_REF(p.first), i, EDIF_REF(cell->name)));
}
}
for (auto &it : net_join_db) {
RTLIL::SigBit sig = it.first;
if (sig.wire == NULL && sig != RTLIL::State::S0 && sig != RTLIL::State::S1)
continue;
std::string netname = log_signal(sig);
for (size_t i = 0; i < netname.size(); i++)
if (netname[i] == ' ' || netname[i] == '\\')
netname.erase(netname.begin() + i--);
*f << stringf(" (net %s (joined\n", EDIF_DEF(netname));
for (auto &ref : it.second)
*f << stringf(" %s\n", ref.c_str());
if (sig.wire == NULL) {
if (nogndvcc)
log_error("Design contains constant nodes (map with \"hilomap\" first).\n");
if (sig == RTLIL::State::S0)
*f << stringf(" (portRef G (instanceRef GND))\n");
if (sig == RTLIL::State::S1)
*f << stringf(" (portRef P (instanceRef VCC))\n");
}
*f << stringf(" ))\n");
}
*f << stringf(" )\n");
*f << stringf(" )\n");
*f << stringf(" )\n");
}
*f << stringf(" )\n");
*f << stringf(" (design %s\n", EDIF_DEF(top_module_name));
*f << stringf(" (cellRef %s (libraryRef DESIGN))\n", EDIF_REF(top_module_name));
*f << stringf(" )\n");
*f << stringf(")\n");
}
} EdifBackend;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,3 @@
OBJS += backends/ilang/ilang_backend.o

View File

@ -0,0 +1,504 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ---
*
* A very simple and straightforward backend for the RTLIL text
* representation (as understood by the 'ilang' frontend).
*
*/
#include "ilang_backend.h"
#include "kernel/yosys.h"
#include <errno.h>
USING_YOSYS_NAMESPACE
using namespace ILANG_BACKEND;
YOSYS_NAMESPACE_BEGIN
void ILANG_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int width, int offset, bool autoint)
{
if (width < 0)
width = data.bits.size() - offset;
if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
if (width == 32 && autoint) {
int32_t val = 0;
for (int i = 0; i < width; i++) {
log_assert(offset+i < (int)data.bits.size());
switch (data.bits[offset+i]) {
case RTLIL::S0: break;
case RTLIL::S1: val |= 1 << i; break;
default: val = -1; break;
}
}
if (val >= 0) {
f << stringf("%d", val);
return;
}
}
f << stringf("%d'", width);
for (int i = offset+width-1; i >= offset; i--) {
log_assert(i < (int)data.bits.size());
switch (data.bits[i]) {
case RTLIL::S0: f << stringf("0"); break;
case RTLIL::S1: f << stringf("1"); break;
case RTLIL::Sx: f << stringf("x"); break;
case RTLIL::Sz: f << stringf("z"); break;
case RTLIL::Sa: f << stringf("-"); break;
case RTLIL::Sm: f << stringf("m"); break;
}
}
} else {
f << stringf("\"");
std::string str = data.decode_string();
for (size_t i = 0; i < str.size(); i++) {
if (str[i] == '\n')
f << stringf("\\n");
else if (str[i] == '\t')
f << stringf("\\t");
else if (str[i] < 32)
f << stringf("\\%03o", str[i]);
else if (str[i] == '"')
f << stringf("\\\"");
else if (str[i] == '\\')
f << stringf("\\\\");
else
f << str[i];
}
f << stringf("\"");
}
}
void ILANG_BACKEND::dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint)
{
if (chunk.wire == NULL) {
dump_const(f, chunk.data, chunk.width, chunk.offset, autoint);
} else {
if (chunk.width == chunk.wire->width && chunk.offset == 0)
f << stringf("%s", chunk.wire->name.c_str());
else if (chunk.width == 1)
f << stringf("%s [%d]", chunk.wire->name.c_str(), chunk.offset);
else
f << stringf("%s [%d:%d]", chunk.wire->name.c_str(), chunk.offset+chunk.width-1, chunk.offset);
}
}
void ILANG_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint)
{
if (sig.is_chunk()) {
dump_sigchunk(f, sig.as_chunk(), autoint);
} else {
f << stringf("{ ");
for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
dump_sigchunk(f, *it, false);
f << stringf(" ");
}
f << stringf("}");
}
}
void ILANG_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire)
{
for (auto &it : wire->attributes) {
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
f << stringf("%s" "wire ", indent.c_str());
if (wire->width != 1)
f << stringf("width %d ", wire->width);
if (wire->upto)
f << stringf("upto ");
if (wire->start_offset != 0)
f << stringf("offset %d ", wire->start_offset);
if (wire->port_input && !wire->port_output)
f << stringf("input %d ", wire->port_id);
if (!wire->port_input && wire->port_output)
f << stringf("output %d ", wire->port_id);
if (wire->port_input && wire->port_output)
f << stringf("inout %d ", wire->port_id);
f << stringf("%s\n", wire->name.c_str());
}
void ILANG_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory)
{
for (auto &it : memory->attributes) {
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
f << stringf("%s" "memory ", indent.c_str());
if (memory->width != 1)
f << stringf("width %d ", memory->width);
if (memory->size != 0)
f << stringf("size %d ", memory->size);
if (memory->start_offset != 0)
f << stringf("offset %d ", memory->start_offset);
f << stringf("%s\n", memory->name.c_str());
}
void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell)
{
for (auto &it : cell->attributes) {
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
for (auto &it : cell->parameters) {
f << stringf("%s parameter%s %s ", indent.c_str(), (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
for (auto &it : cell->connections()) {
f << stringf("%s connect %s ", indent.c_str(), it.first.c_str());
dump_sigspec(f, it.second);
f << stringf("\n");
}
f << stringf("%s" "end\n", indent.c_str());
}
void ILANG_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs)
{
for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it)
{
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, it->first);
f << stringf(" ");
dump_sigspec(f, it->second);
f << stringf("\n");
}
for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
dump_proc_switch(f, indent, *it);
}
void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw)
{
for (auto it = sw->attributes.begin(); it != sw->attributes.end(); ++it) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
f << stringf("\n");
}
f << stringf("%s" "switch ", indent.c_str());
dump_sigspec(f, sw->signal);
f << stringf("\n");
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it)
{
f << stringf("%s case ", indent.c_str());
for (size_t i = 0; i < (*it)->compare.size(); i++) {
if (i > 0)
f << stringf(", ");
dump_sigspec(f, (*it)->compare[i]);
}
f << stringf("\n");
dump_proc_case_body(f, indent + " ", *it);
}
f << stringf("%s" "end\n", indent.c_str());
}
void ILANG_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy)
{
f << stringf("%s" "sync ", indent.c_str());
switch (sy->type) {
if (0) case RTLIL::ST0: f << stringf("low ");
if (0) case RTLIL::ST1: f << stringf("high ");
if (0) case RTLIL::STp: f << stringf("posedge ");
if (0) case RTLIL::STn: f << stringf("negedge ");
if (0) case RTLIL::STe: f << stringf("edge ");
dump_sigspec(f, sy->signal);
f << stringf("\n");
break;
case RTLIL::STa: f << stringf("always\n"); break;
case RTLIL::STg: f << stringf("global\n"); break;
case RTLIL::STi: f << stringf("init\n"); break;
}
for (auto it = sy->actions.begin(); it != sy->actions.end(); ++it) {
f << stringf("%s update ", indent.c_str());
dump_sigspec(f, it->first);
f << stringf(" ");
dump_sigspec(f, it->second);
f << stringf("\n");
}
}
void ILANG_BACKEND::dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc)
{
for (auto it = proc->attributes.begin(); it != proc->attributes.end(); ++it) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
f << stringf("\n");
}
f << stringf("%s" "process %s\n", indent.c_str(), proc->name.c_str());
dump_proc_case_body(f, indent + " ", &proc->root_case);
for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
dump_proc_sync(f, indent + " ", *it);
f << stringf("%s" "end\n", indent.c_str());
}
void ILANG_BACKEND::dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
{
f << stringf("%s" "connect ", indent.c_str());
dump_sigspec(f, left);
f << stringf(" ");
dump_sigspec(f, right);
f << stringf("\n");
}
void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
{
bool print_header = flag_m || design->selected_whole_module(module->name);
bool print_body = !flag_n || !design->selected_whole_module(module->name);
if (print_header)
{
for (auto it = module->attributes.begin(); it != module->attributes.end(); ++it) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
f << stringf("\n");
}
f << stringf("%s" "module %s\n", indent.c_str(), module->name.c_str());
if (!module->avail_parameters.empty()) {
if (only_selected)
f << stringf("\n");
for (auto &p : module->avail_parameters)
f << stringf("%s" " parameter %s\n", indent.c_str(), p.c_str());
}
}
if (print_body)
{
for (auto it : module->wires())
if (!only_selected || design->selected(module, it)) {
if (only_selected)
f << stringf("\n");
dump_wire(f, indent + " ", it);
}
for (auto it : module->memories)
if (!only_selected || design->selected(module, it.second)) {
if (only_selected)
f << stringf("\n");
dump_memory(f, indent + " ", it.second);
}
for (auto it : module->cells())
if (!only_selected || design->selected(module, it)) {
if (only_selected)
f << stringf("\n");
dump_cell(f, indent + " ", it);
}
for (auto it : module->processes)
if (!only_selected || design->selected(module, it.second)) {
if (only_selected)
f << stringf("\n");
dump_proc(f, indent + " ", it.second);
}
bool first_conn_line = true;
for (auto it = module->connections().begin(); it != module->connections().end(); ++it) {
bool show_conn = !only_selected;
if (only_selected) {
RTLIL::SigSpec sigs = it->first;
sigs.append(it->second);
for (auto &c : sigs.chunks()) {
if (c.wire == NULL || !design->selected(module, c.wire))
continue;
show_conn = true;
}
}
if (show_conn) {
if (only_selected && first_conn_line)
f << stringf("\n");
dump_conn(f, indent + " ", it->first, it->second);
first_conn_line = false;
}
}
}
if (print_header)
f << stringf("%s" "end\n", indent.c_str());
}
void ILANG_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
{
#ifndef NDEBUG
int init_autoidx = autoidx;
#endif
if (!flag_m) {
int count_selected_mods = 0;
for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
if (design->selected_whole_module(it->first))
flag_m = true;
if (design->selected(it->second))
count_selected_mods++;
}
if (count_selected_mods > 1)
flag_m = true;
}
if (!only_selected || flag_m) {
if (only_selected)
f << stringf("\n");
f << stringf("autoidx %d\n", autoidx);
}
for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
if (!only_selected || design->selected(it->second)) {
if (only_selected)
f << stringf("\n");
dump_module(f, "", it->second, design, only_selected, flag_m, flag_n);
}
}
log_assert(init_autoidx == autoidx);
}
YOSYS_NAMESPACE_END
PRIVATE_NAMESPACE_BEGIN
struct IlangBackend : public Backend {
IlangBackend() : Backend("ilang", "write design to ilang file") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" write_ilang [filename]\n");
log("\n");
log("Write the current design to an 'ilang' file. (ilang is a text representation\n");
log("of a design in yosys's internal format.)\n");
log("\n");
log(" -selected\n");
log(" only write selected parts of the design.\n");
log("\n");
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
bool selected = false;
log_header(design, "Executing ILANG backend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if (arg == "-selected") {
selected = true;
continue;
}
break;
}
extra_args(f, filename, args, argidx);
design->sort();
log("Output filename: %s\n", filename.c_str());
*f << stringf("# Generated by %s\n", yosys_version_str);
ILANG_BACKEND::dump_design(*f, design, selected, true, false);
}
} IlangBackend;
struct DumpPass : public Pass {
DumpPass() : Pass("dump", "print parts of the design in ilang format") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" dump [options] [selection]\n");
log("\n");
log("Write the selected parts of the design to the console or specified file in\n");
log("ilang format.\n");
log("\n");
log(" -m\n");
log(" also dump the module headers, even if only parts of a single\n");
log(" module is selected\n");
log("\n");
log(" -n\n");
log(" only dump the module headers if the entire module is selected\n");
log("\n");
log(" -o <filename>\n");
log(" write to the specified file.\n");
log("\n");
log(" -a <filename>\n");
log(" like -outfile but append instead of overwrite\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
std::string filename;
bool flag_m = false, flag_n = false, append = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
std::string arg = args[argidx];
if ((arg == "-o" || arg == "-outfile") && argidx+1 < args.size()) {
filename = args[++argidx];
append = false;
continue;
}
if ((arg == "-a" || arg == "-append") && argidx+1 < args.size()) {
filename = args[++argidx];
append = true;
continue;
}
if (arg == "-m") {
flag_m = true;
continue;
}
if (arg == "-n") {
flag_n = true;
continue;
}
break;
}
extra_args(args, argidx, design);
std::ostream *f;
std::stringstream buf;
if (!filename.empty()) {
std::ofstream *ff = new std::ofstream;
ff->open(filename.c_str(), append ? std::ofstream::app : std::ofstream::trunc);
if (ff->fail()) {
delete ff;
log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
}
f = ff;
} else {
f = &buf;
}
ILANG_BACKEND::dump_design(*f, design, true, flag_m, flag_n);
if (!filename.empty()) {
delete f;
} else {
log("%s", buf.str().c_str());
}
}
} DumpPass;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,51 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ---
*
* A very simple and straightforward backend for the RTLIL text
* representation (as understood by the 'ilang' frontend).
*
*/
#ifndef ILANG_BACKEND_H
#define ILANG_BACKEND_H
#include "kernel/yosys.h"
#include <stdio.h>
YOSYS_NAMESPACE_BEGIN
namespace ILANG_BACKEND {
void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool autoint = true);
void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint = true);
void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint = true);
void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);
void dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory);
void dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell);
void dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs);
void dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw);
void dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy);
void dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc);
void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right);
void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false);
void dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false);
}
YOSYS_NAMESPACE_END
#endif

View File

@ -0,0 +1,3 @@
OBJS += backends/intersynth/intersynth.o

View File

@ -0,0 +1,220 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static std::string netname(std::set<std::string> &conntypes_code, std::set<std::string> &celltypes_code, std::set<std::string> &constcells_code, RTLIL::SigSpec sig)
{
if (!sig.is_fully_const() && !sig.is_wire())
log_error("Can't export composite or non-word-wide signal %s.\n", log_signal(sig));
conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.size(), sig.size(), sig.size()));
if (sig.is_fully_const()) {
celltypes_code.insert(stringf("celltype CONST_%d b%d *CONST cfg:%d VALUE\n", sig.size(), sig.size(), sig.size()));
constcells_code.insert(stringf("node CONST_%d_0x%x CONST_%d CONST CONST_%d_0x%x VALUE 0x%x\n",
sig.size(), sig.as_int(), sig.size(), sig.size(), sig.as_int(), sig.as_int()));
return stringf("CONST_%d_0x%x", sig.size(), sig.as_int());
}
return RTLIL::unescape_id(sig.as_wire()->name);
}
struct IntersynthBackend : public Backend {
IntersynthBackend() : Backend("intersynth", "write design to InterSynth netlist file") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" write_intersynth [options] [filename]\n");
log("\n");
log("Write the current design to an 'intersynth' netlist file. InterSynth is\n");
log("a tool for Coarse-Grain Example-Driven Interconnect Synthesis.\n");
log("\n");
log(" -notypes\n");
log(" do not generate celltypes and conntypes commands. i.e. just output\n");
log(" the netlists. this is used for postsilicon synthesis.\n");
log("\n");
log(" -lib <verilog_or_ilang_file>\n");
log(" Use the specified library file for determining whether cell ports are\n");
log(" inputs or outputs. This option can be used multiple times to specify\n");
log(" more than one library.\n");
log("\n");
log(" -selected\n");
log(" only write selected modules. modules must be selected entirely or\n");
log(" not at all.\n");
log("\n");
log("http://www.clifford.at/intersynth/\n");
log("\n");
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
log_header(design, "Executing INTERSYNTH backend.\n");
log_push();
std::vector<std::string> libfiles;
std::vector<RTLIL::Design*> libs;
bool flag_notypes = false;
bool selected = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-notypes") {
flag_notypes = true;
continue;
}
if (args[argidx] == "-lib" && argidx+1 < args.size()) {
libfiles.push_back(args[++argidx]);
continue;
}
if (args[argidx] == "-selected") {
selected = true;
continue;
}
break;
}
extra_args(f, filename, args, argidx);
log("Output filename: %s\n", filename.c_str());
for (auto filename : libfiles) {
std::ifstream f;
f.open(filename.c_str());
if (f.fail())
log_error("Can't open lib file `%s'.\n", filename.c_str());
RTLIL::Design *lib = new RTLIL::Design;
Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
libs.push_back(lib);
}
if (libs.size() > 0)
log_header(design, "Continuing INTERSYNTH backend.\n");
std::set<std::string> conntypes_code, celltypes_code;
std::string netlists_code;
CellTypes ct(design);
for (auto lib : libs)
ct.setup_design(lib);
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
SigMap sigmap(module);
if (module->get_bool_attribute("\\blackbox"))
continue;
if (module->memories.size() == 0 && module->processes.size() == 0 && module->cells_.size() == 0)
continue;
if (selected && !design->selected_whole_module(module->name)) {
if (design->selected_module(module->name))
log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(module->name));
continue;
}
log("Generating netlist %s.\n", RTLIL::id2cstr(module->name));
if (module->memories.size() != 0 || module->processes.size() != 0)
log_error("Can't generate a netlist for a module with unprocessed memories or processes!\n");
std::set<std::string> constcells_code;
netlists_code += stringf("# Netlist of module %s\n", RTLIL::id2cstr(module->name));
netlists_code += stringf("netlist %s\n", RTLIL::id2cstr(module->name));
// Module Ports: "std::set<string> celltypes_code" prevents duplicate top level ports
for (auto wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_input || wire->port_output) {
celltypes_code.insert(stringf("celltype !%s b%d %sPORT\n" "%s %s %d %s PORT\n",
RTLIL::id2cstr(wire->name), wire->width, wire->port_input ? "*" : "",
wire->port_input ? "input" : "output", RTLIL::id2cstr(wire->name), wire->width, RTLIL::id2cstr(wire->name)));
netlists_code += stringf("node %s %s PORT %s\n", RTLIL::id2cstr(wire->name), RTLIL::id2cstr(wire->name),
netname(conntypes_code, celltypes_code, constcells_code, sigmap(wire)).c_str());
}
}
// Submodules: "std::set<string> celltypes_code" prevents duplicate cell types
for (auto cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
std::string celltype_code, node_code;
if (!ct.cell_known(cell->type))
log_error("Found unknown cell type %s in module!\n", RTLIL::id2cstr(cell->type));
celltype_code = stringf("celltype %s", RTLIL::id2cstr(cell->type));
node_code = stringf("node %s %s", RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
for (auto &port : cell->connections()) {
RTLIL::SigSpec sig = sigmap(port.second);
if (sig.size() != 0) {
conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.size(), sig.size(), sig.size()));
celltype_code += stringf(" b%d %s%s", sig.size(), ct.cell_output(cell->type, port.first) ? "*" : "", RTLIL::id2cstr(port.first));
node_code += stringf(" %s %s", RTLIL::id2cstr(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig).c_str());
}
}
for (auto &param : cell->parameters) {
celltype_code += stringf(" cfg:%d %s", int(param.second.bits.size()), RTLIL::id2cstr(param.first));
if (param.second.bits.size() != 32) {
node_code += stringf(" %s '", RTLIL::id2cstr(param.first));
for (int i = param.second.bits.size()-1; i >= 0; i--)
node_code += param.second.bits[i] == RTLIL::S1 ? "1" : "0";
} else
node_code += stringf(" %s 0x%x", RTLIL::id2cstr(param.first), param.second.as_int());
}
celltypes_code.insert(celltype_code + "\n");
netlists_code += node_code + "\n";
}
if (constcells_code.size() > 0)
netlists_code += "# constant cells\n";
for (auto code : constcells_code)
netlists_code += code;
netlists_code += "\n";
}
if (!flag_notypes) {
*f << stringf("### Connection Types\n");
for (auto code : conntypes_code)
*f << stringf("%s", code.c_str());
*f << stringf("\n### Cell Types\n");
for (auto code : celltypes_code)
*f << stringf("%s", code.c_str());
}
*f << stringf("\n### Netlists\n");
*f << stringf("%s", netlists_code.c_str());
for (auto lib : libs)
delete lib;
log_pop();
}
} IntersynthBackend;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,3 @@
OBJS += backends/json/json.o

542
yosys/backends/json/json.cc Normal file
View File

@ -0,0 +1,542 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/cellaigs.h"
#include "kernel/log.h"
#include <string>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct JsonWriter
{
std::ostream &f;
bool use_selection;
bool aig_mode;
Design *design;
Module *module;
SigMap sigmap;
int sigidcounter;
dict<SigBit, string> sigids;
pool<Aig> aig_models;
JsonWriter(std::ostream &f, bool use_selection, bool aig_mode) :
f(f), use_selection(use_selection), aig_mode(aig_mode) { }
string get_string(string str)
{
string newstr = "\"";
for (char c : str) {
if (c == '\\')
newstr += c;
newstr += c;
}
return newstr + "\"";
}
string get_name(IdString name)
{
return get_string(RTLIL::unescape_id(name));
}
string get_bits(SigSpec sig)
{
bool first = true;
string str = "[";
for (auto bit : sigmap(sig)) {
str += first ? " " : ", ";
first = false;
if (sigids.count(bit) == 0) {
string &s = sigids[bit];
if (bit.wire == nullptr) {
if (bit == State::S0) s = "\"0\"";
else if (bit == State::S1) s = "\"1\"";
else if (bit == State::Sz) s = "\"z\"";
else s = "\"x\"";
} else
s = stringf("%d", sigidcounter++);
}
str += sigids[bit];
}
return str + " ]";
}
void write_parameters(const dict<IdString, Const> &parameters, bool for_module=false)
{
bool first = true;
for (auto &param : parameters) {
f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s%s: ", for_module ? "" : " ", get_name(param.first).c_str());
if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0)
f << get_string(param.second.decode_string());
else if (GetSize(param.second.bits) > 32)
f << get_string(param.second.as_string());
else
f << stringf("%d", param.second.as_int());
first = false;
}
}
void write_module(Module *module_)
{
module = module_;
log_assert(module->design == design);
sigmap.set(module);
sigids.clear();
// reserve 0 and 1 to avoid confusion with "0" and "1"
sigidcounter = 2;
f << stringf(" %s: {\n", get_name(module->name).c_str());
f << stringf(" \"attributes\": {");
write_parameters(module->attributes, /*for_module=*/true);
f << stringf("\n },\n");
f << stringf(" \"ports\": {");
bool first = true;
for (auto n : module->ports) {
Wire *w = module->wire(n);
if (use_selection && !module->selected(w))
continue;
f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s: {\n", get_name(n).c_str());
f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output");
f << stringf(" \"bits\": %s\n", get_bits(w).c_str());
f << stringf(" }");
first = false;
}
f << stringf("\n },\n");
f << stringf(" \"cells\": {");
first = true;
for (auto c : module->cells()) {
if (use_selection && !module->selected(c))
continue;
f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s: {\n", get_name(c->name).c_str());
f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0");
f << stringf(" \"type\": %s,\n", get_name(c->type).c_str());
if (aig_mode) {
Aig aig(c);
if (!aig.name.empty()) {
f << stringf(" \"model\": \"%s\",\n", aig.name.c_str());
aig_models.insert(aig);
}
}
f << stringf(" \"parameters\": {");
write_parameters(c->parameters);
f << stringf("\n },\n");
f << stringf(" \"attributes\": {");
write_parameters(c->attributes);
f << stringf("\n },\n");
if (c->known()) {
f << stringf(" \"port_directions\": {");
bool first2 = true;
for (auto &conn : c->connections()) {
string direction = "output";
if (c->input(conn.first))
direction = c->output(conn.first) ? "inout" : "input";
f << stringf("%s\n", first2 ? "" : ",");
f << stringf(" %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str());
first2 = false;
}
f << stringf("\n },\n");
}
f << stringf(" \"connections\": {");
bool first2 = true;
for (auto &conn : c->connections()) {
f << stringf("%s\n", first2 ? "" : ",");
f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str());
first2 = false;
}
f << stringf("\n }\n");
f << stringf(" }");
first = false;
}
f << stringf("\n },\n");
f << stringf(" \"netnames\": {");
first = true;
for (auto w : module->wires()) {
if (use_selection && !module->selected(w))
continue;
f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s: {\n", get_name(w->name).c_str());
f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
f << stringf(" \"bits\": %s,\n", get_bits(w).c_str());
f << stringf(" \"attributes\": {");
write_parameters(w->attributes);
f << stringf("\n }\n");
f << stringf(" }");
first = false;
}
f << stringf("\n }\n");
f << stringf(" }");
}
void write_design(Design *design_)
{
design = design_;
f << stringf("{\n");
f << stringf(" \"creator\": %s,\n", get_string(yosys_version_str).c_str());
f << stringf(" \"modules\": {\n");
vector<Module*> modules = use_selection ? design->selected_modules() : design->modules();
bool first_module = true;
for (auto mod : modules) {
if (!first_module)
f << stringf(",\n");
write_module(mod);
first_module = false;
}
f << stringf("\n }");
if (!aig_models.empty()) {
f << stringf(",\n \"models\": {\n");
bool first_model = true;
for (auto &aig : aig_models) {
if (!first_model)
f << stringf(",\n");
f << stringf(" \"%s\": [\n", aig.name.c_str());
int node_idx = 0;
for (auto &node : aig.nodes) {
if (node_idx != 0)
f << stringf(",\n");
f << stringf(" /* %3d */ [ ", node_idx);
if (node.portbit >= 0)
f << stringf("\"%sport\", \"%s\", %d", node.inverter ? "n" : "",
log_id(node.portname), node.portbit);
else if (node.left_parent < 0 && node.right_parent < 0)
f << stringf("\"%s\"", node.inverter ? "true" : "false");
else
f << stringf("\"%s\", %d, %d", node.inverter ? "nand" : "and", node.left_parent, node.right_parent);
for (auto &op : node.outports)
f << stringf(", \"%s\", %d", log_id(op.first), op.second);
f << stringf(" ]");
node_idx++;
}
f << stringf("\n ]");
first_model = false;
}
f << stringf("\n }");
}
f << stringf("\n}\n");
}
};
struct JsonBackend : public Backend {
JsonBackend() : Backend("json", "write design to a JSON file") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" write_json [options] [filename]\n");
log("\n");
log("Write a JSON netlist of the current design.\n");
log("\n");
log(" -aig\n");
log(" include AIG models for the different gate types\n");
log("\n");
log("\n");
log("The general syntax of the JSON output created by this command is as follows:\n");
log("\n");
log(" {\n");
log(" \"modules\": {\n");
log(" <module_name>: {\n");
log(" \"ports\": {\n");
log(" <port_name>: <port_details>,\n");
log(" ...\n");
log(" },\n");
log(" \"cells\": {\n");
log(" <cell_name>: <cell_details>,\n");
log(" ...\n");
log(" },\n");
log(" \"netnames\": {\n");
log(" <net_name>: <net_details>,\n");
log(" ...\n");
log(" }\n");
log(" }\n");
log(" },\n");
log(" \"models\": {\n");
log(" ...\n");
log(" },\n");
log(" }\n");
log("\n");
log("Where <port_details> is:\n");
log("\n");
log(" {\n");
log(" \"direction\": <\"input\" | \"output\" | \"inout\">,\n");
log(" \"bits\": <bit_vector>\n");
log(" }\n");
log("\n");
log("And <cell_details> is:\n");
log("\n");
log(" {\n");
log(" \"hide_name\": <1 | 0>,\n");
log(" \"type\": <cell_type>,\n");
log(" \"parameters\": {\n");
log(" <parameter_name>: <parameter_value>,\n");
log(" ...\n");
log(" },\n");
log(" \"attributes\": {\n");
log(" <attribute_name>: <attribute_value>,\n");
log(" ...\n");
log(" },\n");
log(" \"port_directions\": {\n");
log(" <port_name>: <\"input\" | \"output\" | \"inout\">,\n");
log(" ...\n");
log(" },\n");
log(" \"connections\": {\n");
log(" <port_name>: <bit_vector>,\n");
log(" ...\n");
log(" },\n");
log(" }\n");
log("\n");
log("And <net_details> is:\n");
log("\n");
log(" {\n");
log(" \"hide_name\": <1 | 0>,\n");
log(" \"bits\": <bit_vector>\n");
log(" }\n");
log("\n");
log("The \"hide_name\" fields are set to 1 when the name of this cell or net is\n");
log("automatically created and is likely not of interest for a regular user.\n");
log("\n");
log("The \"port_directions\" section is only included for cells for which the\n");
log("interface is known.\n");
log("\n");
log("Module and cell ports and nets can be single bit wide or vectors of multiple\n");
log("bits. Each individual signal bit is assigned a unique integer. The <bit_vector>\n");
log("values referenced above are vectors of this integers. Signal bits that are\n");
log("connected to a constant driver are denoted as string \"0\" or \"1\" instead of\n");
log("a number.\n");
log("\n");
log("For example the following Verilog code:\n");
log("\n");
log(" module test(input x, y);\n");
log(" (* keep *) foo #(.P(42), .Q(1337))\n");
log(" foo_inst (.A({x, y}), .B({y, x}), .C({4'd10, {4{x}}}));\n");
log(" endmodule\n");
log("\n");
log("Translates to the following JSON output:\n");
log("\n");
log(" {\n");
log(" \"modules\": {\n");
log(" \"test\": {\n");
log(" \"ports\": {\n");
log(" \"x\": {\n");
log(" \"direction\": \"input\",\n");
log(" \"bits\": [ 2 ]\n");
log(" },\n");
log(" \"y\": {\n");
log(" \"direction\": \"input\",\n");
log(" \"bits\": [ 3 ]\n");
log(" }\n");
log(" },\n");
log(" \"cells\": {\n");
log(" \"foo_inst\": {\n");
log(" \"hide_name\": 0,\n");
log(" \"type\": \"foo\",\n");
log(" \"parameters\": {\n");
log(" \"Q\": 1337,\n");
log(" \"P\": 42\n");
log(" },\n");
log(" \"attributes\": {\n");
log(" \"keep\": 1,\n");
log(" \"src\": \"test.v:2\"\n");
log(" },\n");
log(" \"connections\": {\n");
log(" \"C\": [ 2, 2, 2, 2, \"0\", \"1\", \"0\", \"1\" ],\n");
log(" \"B\": [ 2, 3 ],\n");
log(" \"A\": [ 3, 2 ]\n");
log(" }\n");
log(" }\n");
log(" },\n");
log(" \"netnames\": {\n");
log(" \"y\": {\n");
log(" \"hide_name\": 0,\n");
log(" \"bits\": [ 3 ],\n");
log(" \"attributes\": {\n");
log(" \"src\": \"test.v:1\"\n");
log(" }\n");
log(" },\n");
log(" \"x\": {\n");
log(" \"hide_name\": 0,\n");
log(" \"bits\": [ 2 ],\n");
log(" \"attributes\": {\n");
log(" \"src\": \"test.v:1\"\n");
log(" }\n");
log(" }\n");
log(" }\n");
log(" }\n");
log(" }\n");
log(" }\n");
log("\n");
log("The models are given as And-Inverter-Graphs (AIGs) in the following form:\n");
log("\n");
log(" \"models\": {\n");
log(" <model_name>: [\n");
log(" /* 0 */ [ <node-spec> ],\n");
log(" /* 1 */ [ <node-spec> ],\n");
log(" /* 2 */ [ <node-spec> ],\n");
log(" ...\n");
log(" ],\n");
log(" ...\n");
log(" },\n");
log("\n");
log("The following node-types may be used:\n");
log("\n");
log(" [ \"port\", <portname>, <bitindex>, <out-list> ]\n");
log(" - the value of the specified input port bit\n");
log("\n");
log(" [ \"nport\", <portname>, <bitindex>, <out-list> ]\n");
log(" - the inverted value of the specified input port bit\n");
log("\n");
log(" [ \"and\", <node-index>, <node-index>, <out-list> ]\n");
log(" - the ANDed value of the specified nodes\n");
log("\n");
log(" [ \"nand\", <node-index>, <node-index>, <out-list> ]\n");
log(" - the inverted ANDed value of the specified nodes\n");
log("\n");
log(" [ \"true\", <out-list> ]\n");
log(" - the constant value 1\n");
log("\n");
log(" [ \"false\", <out-list> ]\n");
log(" - the constant value 0\n");
log("\n");
log("All nodes appear in topological order. I.e. only nodes with smaller indices\n");
log("are referenced by \"and\" and \"nand\" nodes.\n");
log("\n");
log("The optional <out-list> at the end of a node specification is a list of\n");
log("output portname and bitindex pairs, specifying the outputs driven by this node.\n");
log("\n");
log("For example, the following is the model for a 3-input 3-output $reduce_and cell\n");
log("inferred by the following code:\n");
log("\n");
log(" module test(input [2:0] in, output [2:0] out);\n");
log(" assign in = &out;\n");
log(" endmodule\n");
log("\n");
log(" \"$reduce_and:3U:3\": [\n");
log(" /* 0 */ [ \"port\", \"A\", 0 ],\n");
log(" /* 1 */ [ \"port\", \"A\", 1 ],\n");
log(" /* 2 */ [ \"and\", 0, 1 ],\n");
log(" /* 3 */ [ \"port\", \"A\", 2 ],\n");
log(" /* 4 */ [ \"and\", 2, 3, \"Y\", 0 ],\n");
log(" /* 5 */ [ \"false\", \"Y\", 1, \"Y\", 2 ]\n");
log(" ]\n");
log("\n");
log("Future version of Yosys might add support for additional fields in the JSON\n");
log("format. A program processing this format must ignore all unknown fields.\n");
log("\n");
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
bool aig_mode = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-aig") {
aig_mode = true;
continue;
}
break;
}
extra_args(f, filename, args, argidx);
log_header(design, "Executing JSON backend.\n");
JsonWriter json_writer(*f, false, aig_mode);
json_writer.write_design(design);
}
} JsonBackend;
struct JsonPass : public Pass {
JsonPass() : Pass("json", "write design in JSON format") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" json [options] [selection]\n");
log("\n");
log("Write a JSON netlist of all selected objects.\n");
log("\n");
log(" -o <filename>\n");
log(" write to the specified file.\n");
log("\n");
log(" -aig\n");
log(" also include AIG models for the different gate types\n");
log("\n");
log("See 'help write_json' for a description of the JSON format used.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
std::string filename;
bool aig_mode = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-o" && argidx+1 < args.size()) {
filename = args[++argidx];
continue;
}
if (args[argidx] == "-aig") {
aig_mode = true;
continue;
}
break;
}
extra_args(args, argidx, design);
std::ostream *f;
std::stringstream buf;
if (!filename.empty()) {
std::ofstream *ff = new std::ofstream;
ff->open(filename.c_str(), std::ofstream::trunc);
if (ff->fail()) {
delete ff;
log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
}
f = ff;
} else {
f = &buf;
}
JsonWriter json_writer(*f, true, aig_mode);
json_writer.write_design(design);
if (!filename.empty()) {
delete f;
} else {
log("%s", buf.str().c_str());
}
}
} JsonPass;
PRIVATE_NAMESPACE_END

1
yosys/backends/smt2/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
test_cells

View File

@ -0,0 +1,16 @@
OBJS += backends/smt2/smt2.o
ifneq ($(CONFIG),mxe)
ifneq ($(CONFIG),emcc)
TARGETS += yosys-smtbmc
yosys-smtbmc: backends/smt2/smtbmc.py
$(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(__file__) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
$(Q) chmod +x $@.new
$(Q) mv $@.new $@
$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py))
endif
endif

View File

@ -0,0 +1,11 @@
module main(input clk);
reg [3:0] counter = 0;
always @(posedge clk) begin
if (counter == 10)
counter <= 0;
else
counter <= counter + 1;
end
assert property (counter != 15);
// assert property (counter <= 10);
endmodule

View File

@ -0,0 +1,3 @@
read_verilog -formal example.v
hierarchy; proc; opt; memory -nordff -nomap; opt -fast
write_smt2 -bv -mem -wires example.smt2

1096
yosys/backends/smt2/smt2.cc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,734 @@
#!/usr/bin/env python3
#
# yosys -- Yosys Open SYnthesis Suite
#
# Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
import os, sys, getopt, re
##yosys-sys-path##
from smtio import SmtIo, SmtOpts, MkVcd
from collections import defaultdict
skip_steps = 0
step_size = 1
num_steps = 20
vcdfile = None
cexfile = None
vlogtbfile = None
inconstr = list()
outconstr = None
gentrace = False
tempind = False
dumpall = False
assume_skipped = None
final_only = False
topmod = None
noinfo = False
so = SmtOpts()
def usage():
print("""
yosys-smtbmc [options] <yosys_smt2_output>
-t <num_steps>
-t <skip_steps>:<num_steps>
-t <skip_steps>:<step_size>:<num_steps>
default: skip_steps=0, step_size=1, num_steps=20
-g
generate an arbitrary trace that satisfies
all assertions and assumptions.
-i
instead of BMC run temporal induction
-m <module_name>
name of the top module
--smtc <constr_filename>
read constraints file
--cex <cex_filename>
read cex file as written by ABC's "write_cex -n"
--noinfo
only run the core proof, do not collect and print any
additional information (e.g. which assert failed)
--final-only
only check final constraints, assume base case
--assume-skipped <start_step>
assume asserts in skipped steps in BMC.
no assumptions are created for skipped steps
before <start_step>.
--dump-vcd <vcd_filename>
write trace to this VCD file
(hint: use 'write_smt2 -wires' for maximum
coverage of signals in generated VCD file)
--dump-vlogtb <verilog_filename>
write trace as Verilog test bench
--dump-smtc <constr_filename>
write trace as constraints file
--dump-all
when using -g or -i, create a dump file for each
step. The character '%' is replaces in all dump
filenames with the step number.
""" + so.helpmsg())
sys.exit(1)
try:
opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igm:", so.longopts +
["final-only", "assume-skipped=", "smtc=", "cex=", "dump-vcd=", "dump-vlogtb=", "dump-smtc=", "dump-all", "noinfo"])
except:
usage()
for o, a in opts:
if o == "-t":
a = a.split(":")
if len(a) == 1:
num_steps = int(a[0])
elif len(a) == 2:
skip_steps = int(a[0])
num_steps = int(a[1])
elif len(a) == 3:
skip_steps = int(a[0])
step_size = int(a[1])
num_steps = int(a[2])
else:
assert 0
elif o == "--assume-skipped":
assume_skipped = int(a)
elif o == "--final-only":
final_only = True
elif o == "--smtc":
inconstr.append(a)
elif o == "--cex":
cexfile = a
elif o == "--dump-vcd":
vcdfile = a
elif o == "--dump-vlogtb":
vlogtbfile = a
elif o == "--dump-smtc":
outconstr = a
elif o == "--dump-all":
dumpall = True
elif o == "--noinfo":
noinfo = True
elif o == "-i":
tempind = True
elif o == "-g":
gentrace = True
elif o == "-m":
topmod = a
elif so.handle(o, a):
pass
else:
usage()
if len(args) != 1:
usage()
constr_final_start = None
constr_asserts = defaultdict(list)
constr_assumes = defaultdict(list)
constr_write = list()
for fn in inconstr:
current_states = None
current_line = 0
with open(fn, "r") as f:
for line in f:
current_line += 1
if line.startswith("#"):
continue
tokens = line.split()
if len(tokens) == 0:
continue
if tokens[0] == "initial":
current_states = set()
if not tempind:
current_states.add(0)
continue
if tokens[0] == "final":
constr_final = True
if len(tokens) == 1:
current_states = set(["final-%d" % i for i in range(0, num_steps+1)])
constr_final_start = 0
elif len(tokens) == 2:
i = int(tokens[1])
assert i < 0
current_states = set(["final-%d" % i for i in range(-i, num_steps+1)])
constr_final_start = -i if constr_final_start is None else min(constr_final_start, -i)
else:
assert 0
continue
if tokens[0] == "state":
current_states = set()
if not tempind:
for token in tokens[1:]:
tok = token.split(":")
if len(tok) == 1:
current_states.add(int(token))
elif len(tok) == 2:
lower = int(tok[0])
if tok[1] == "*":
upper = num_steps
else:
upper = int(tok[1])
for i in range(lower, upper+1):
current_states.add(i)
else:
assert 0
continue
if tokens[0] == "always":
if len(tokens) == 1:
current_states = set(range(0, num_steps+1))
elif len(tokens) == 2:
i = int(tokens[1])
assert i < 0
current_states = set(range(-i, num_steps+1))
else:
assert 0
continue
if tokens[0] == "assert":
assert current_states is not None
for state in current_states:
constr_asserts[state].append(("%s:%d" % (fn, current_line), " ".join(tokens[1:])))
continue
if tokens[0] == "assume":
assert current_states is not None
for state in current_states:
constr_assumes[state].append(("%s:%d" % (fn, current_line), " ".join(tokens[1:])))
continue
if tokens[0] == "write":
constr_write.append(" ".join(tokens[1:]))
continue
if tokens[0] == "logic":
so.logic = " ".join(tokens[1:])
continue
assert 0
def get_constr_expr(db, state, final=False, getvalues=False):
if final:
if ("final-%d" % state) not in db:
return ([], [], []) if getvalues else "true"
else:
if state not in db:
return ([], [], []) if getvalues else "true"
netref_regex = re.compile(r'(^|[( ])\[(-?[0-9]+:|)([^\]]*)\](?=[ )]|$)')
def replace_netref(match):
state_sel = match.group(2)
if state_sel == "":
st = state
elif state_sel[0] == "-":
st = state + int(state_sel[:-1])
else:
st = int(state_sel[:-1])
expr = smt.net_expr(topmod, "s%d" % st, smt.get_path(topmod, match.group(3)))
return match.group(1) + expr
expr_list = list()
for loc, expr in db[("final-%d" % state) if final else state]:
actual_expr = netref_regex.sub(replace_netref, expr)
if getvalues:
expr_list.append((loc, expr, actual_expr))
else:
expr_list.append(actual_expr)
if getvalues:
loc_list, expr_list, acual_expr_list = zip(*expr_list)
value_list = smt.get_list(acual_expr_list)
return loc_list, expr_list, value_list
if len(expr_list) == 0:
return "true"
if len(expr_list) == 1:
return expr_list[0]
return "(and %s)" % " ".join(expr_list)
smt = SmtIo(opts=so)
if noinfo and vcdfile is None and vlogtbfile is None and outconstr is None:
smt.produce_models = False
def print_msg(msg):
print("%s %s" % (smt.timestamp(), msg))
sys.stdout.flush()
print_msg("Solver: %s" % (so.solver))
with open(args[0], "r") as f:
for line in f:
smt.write(line)
for line in constr_write:
smt.write(line)
if topmod is None:
topmod = smt.topmod
assert topmod is not None
assert topmod in smt.modinfo
if cexfile is not None:
with open(cexfile, "r") as f:
cex_regex = re.compile(r'([^\[@=]+)(\[\d+\])?([^@=]*)(@\d+)=([01])')
for entry in f.read().split():
match = cex_regex.match(entry)
assert match
name, bit, extra_name, step, val = match.group(1), match.group(2), match.group(3), match.group(4), match.group(5)
if extra_name != "":
continue
if name not in smt.modinfo[topmod].inputs:
continue
if bit is None:
bit = 0
else:
bit = int(bit[1:-1])
step = int(step[1:])
val = int(val)
if smt.modinfo[topmod].wsize[name] == 1:
assert bit == 0
smtexpr = "(= [%s] %s)" % (name, "true" if val else "false")
else:
smtexpr = "(= ((_ extract %d %d) [%s]) #b%d)" % (bit, bit, name, val)
# print("cex@%d: %s" % (step, smtexpr))
constr_assumes[step].append((cexfile, smtexpr))
def write_vcd_trace(steps_start, steps_stop, index):
filename = vcdfile.replace("%", index)
print_msg("Writing trace to VCD file: %s" % (filename))
with open(filename, "w") as vcd_file:
vcd = MkVcd(vcd_file)
path_list = list()
for netpath in sorted(smt.hiernets(topmod)):
hidden_net = False
for n in netpath:
if n.startswith("$"):
hidden_net = True
if not hidden_net:
vcd.add_net([topmod] + netpath, smt.net_width(topmod, netpath))
path_list.append(netpath)
for i in range(steps_start, steps_stop):
vcd.set_time(i)
value_list = smt.get_net_bin_list(topmod, path_list, "s%d" % i)
for path, value in zip(path_list, value_list):
vcd.set_net([topmod] + path, value)
vcd.set_time(steps_stop)
def write_vlogtb_trace(steps_start, steps_stop, index):
filename = vlogtbfile.replace("%", index)
print_msg("Writing trace to Verilog testbench: %s" % (filename))
with open(filename, "w") as f:
print("module testbench;", file=f)
print(" reg [4095:0] vcdfile;", file=f)
print(" reg clock = 0, genclock = 1;", file=f)
primary_inputs = list()
clock_inputs = set()
for name in smt.modinfo[topmod].inputs:
if name in ["clk", "clock", "CLK", "CLOCK"]:
clock_inputs.add(name)
width = smt.modinfo[topmod].wsize[name]
primary_inputs.append((name, width))
for name, width in primary_inputs:
if name in clock_inputs:
print(" wire [%d:0] PI_%s = clock;" % (width-1, name), file=f)
else:
print(" reg [%d:0] PI_%s;" % (width-1, name), file=f)
print(" %s UUT (" % topmod, file=f)
print(",\n".join(" .{name}(PI_{name})".format(name=name) for name, _ in primary_inputs), file=f)
print(" );", file=f)
print(" initial begin", file=f)
print(" if ($value$plusargs(\"vcd=%s\", vcdfile)) begin", file=f)
print(" $dumpfile(vcdfile);", file=f)
print(" $dumpvars(0, testbench);", file=f)
print(" end", file=f)
print(" while (genclock) begin", file=f)
print(" #5; clock = 0;", file=f)
print(" #5; clock = 1;", file=f)
print(" end", file=f)
print(" end", file=f)
print(" initial begin", file=f)
regs = sorted(smt.hiernets(topmod, regs_only=True))
regvals = smt.get_net_bin_list(topmod, regs, "s%d" % steps_start)
print(" #1;", file=f)
for reg, val in zip(regs, regvals):
hidden_net = False
for n in reg:
if n.startswith("$"):
hidden_net = True
print(" %sUUT.%s = %d'b%s;" % ("// " if hidden_net else "", ".".join(reg), len(val), val), file=f)
mems = sorted(smt.hiermems(topmod))
for mempath in mems:
abits, width, ports = smt.mem_info(topmod, "s%d" % steps_start, mempath)
mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath)
addr_expr_list = list()
for i in range(steps_start, steps_stop):
for j in range(ports):
addr_expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, j))
addr_list = set()
for val in smt.get_list(addr_expr_list):
addr_list.add(smt.bv2int(val))
expr_list = list()
for i in addr_list:
expr_list.append("(select %s #b%s)" % (mem, format(i, "0%db" % abits)))
for i, val in zip(addr_list, smt.get_list(expr_list)):
val = smt.bv2bin(val)
print(" UUT.%s[%d] = %d'b%s;" % (".".join(mempath), i, len(val), val), file=f)
for i in range(steps_start, steps_stop):
pi_names = [[name] for name, _ in primary_inputs if name not in clock_inputs]
pi_values = smt.get_net_bin_list(topmod, pi_names, "s%d" % i)
print(" #1;", file=f)
print(" // state %d" % i, file=f)
if i > 0:
print(" @(posedge clock);", file=f)
for name, val in zip(pi_names, pi_values):
print(" PI_%s <= %d'b%s;" % (".".join(name), len(val), val), file=f)
print(" genclock = 0;", file=f)
print(" end", file=f)
print("endmodule", file=f)
def write_constr_trace(steps_start, steps_stop, index):
filename = outconstr.replace("%", index)
print_msg("Writing trace to constraints file: %s" % (filename))
with open(filename, "w") as f:
primary_inputs = list()
for name in smt.modinfo[topmod].inputs:
width = smt.modinfo[topmod].wsize[name]
primary_inputs.append((name, width))
if steps_start == 0:
print("initial", file=f)
else:
print("state %d" % steps_start, file=f)
regnames = sorted(smt.hiernets(topmod, regs_only=True))
regvals = smt.get_net_list(topmod, regnames, "s%d" % steps_start)
for name, val in zip(regnames, regvals):
print("assume (= [%s] %s)" % (".".join(name), val), file=f)
mems = sorted(smt.hiermems(topmod))
for mempath in mems:
abits, width, ports = smt.mem_info(topmod, "s%d" % steps_start, mempath)
mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath)
addr_expr_list = list()
for i in range(steps_start, steps_stop):
for j in range(ports):
addr_expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, j))
addr_list = set((smt.bv2int(val) for val in smt.get_list(addr_expr_list)))
expr_list = list()
for i in addr_list:
expr_list.append("(select %s #b%s)" % (mem, format(i, "0%db" % abits)))
for i, val in zip(addr_list, smt.get_list(expr_list)):
print("assume (= (select [%s] #b%s) %s)" % (".".join(mempath), format(i, "0%db" % abits), val), file=f)
for k in range(steps_start, steps_stop):
print("", file=f)
print("state %d" % k, file=f)
pi_names = [[name] for name, _ in sorted(primary_inputs)]
pi_values = smt.get_net_list(topmod, pi_names, "s%d" % k)
for name, val in zip(pi_names, pi_values):
print("assume (= [%s] %s)" % (".".join(name), val), file=f)
def write_trace(steps_start, steps_stop, index):
if vcdfile is not None:
write_vcd_trace(steps_start, steps_stop, index)
if vlogtbfile is not None:
write_vlogtb_trace(steps_start, steps_stop, index)
if outconstr is not None:
write_constr_trace(steps_start, steps_stop, index)
def print_failed_asserts_worker(mod, state, path):
assert mod in smt.modinfo
if smt.get("(|%s_a| %s)" % (mod, state)) in ["true", "#b1"]:
return
for cellname, celltype in smt.modinfo[mod].cells.items():
print_failed_asserts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname)
for assertfun, assertinfo in smt.modinfo[mod].asserts.items():
if smt.get("(|%s| %s)" % (assertfun, state)) in ["false", "#b0"]:
print_msg("Assert failed in %s: %s" % (path, assertinfo))
def print_failed_asserts(state, final=False):
if noinfo: return
loc_list, expr_list, value_list = get_constr_expr(constr_asserts, state, final=final, getvalues=True)
for loc, expr, value in zip(loc_list, expr_list, value_list):
if smt.bv2int(value) == 0:
print_msg("Assert %s failed: %s" % (loc, expr))
if not final:
print_failed_asserts_worker(topmod, "s%d" % state, topmod)
def print_anyconsts_worker(mod, state, path):
assert mod in smt.modinfo
for cellname, celltype in smt.modinfo[mod].cells.items():
print_anyconsts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname)
for fun, info in smt.modinfo[mod].anyconsts.items():
print_msg("Value for anyconst in %s (%s): %d" % (path, info, smt.bv2int(smt.get("(|%s| %s)" % (fun, state)))))
def print_anyconsts(state):
if noinfo: return
print_anyconsts_worker(topmod, "s%d" % state, topmod)
if tempind:
retstatus = False
skip_counter = step_size
for step in range(num_steps, -1, -1):
smt.write("(declare-fun s%d () |%s_s|)" % (step, topmod))
smt.write("(assert (|%s_u| s%d))" % (topmod, step))
smt.write("(assert (|%s_h| s%d))" % (topmod, step))
smt.write("(assert (not (|%s_is| s%d)))" % (topmod, step))
smt.write("(assert %s)" % get_constr_expr(constr_assumes, step))
if step == num_steps:
smt.write("(assert (not (and (|%s_a| s%d) %s)))" % (topmod, step, get_constr_expr(constr_asserts, step)))
else:
smt.write("(assert (|%s_t| s%d s%d))" % (topmod, step, step+1))
smt.write("(assert (|%s_a| s%d))" % (topmod, step))
smt.write("(assert %s)" % get_constr_expr(constr_asserts, step))
if step > num_steps-skip_steps:
print_msg("Skipping induction in step %d.." % (step))
continue
skip_counter += 1
if skip_counter < step_size:
print_msg("Skipping induction in step %d.." % (step))
continue
skip_counter = 0
print_msg("Trying induction in step %d.." % (step))
if smt.check_sat() == "sat":
if step == 0:
print("%s Temporal induction failed!" % smt.timestamp())
print_anyconsts(num_steps)
print_failed_asserts(num_steps)
write_trace(step, num_steps+1, '%')
elif dumpall:
print_anyconsts(num_steps)
print_failed_asserts(num_steps)
write_trace(step, num_steps+1, "%d" % step)
else:
print("%s Temporal induction successful." % smt.timestamp())
retstatus = True
break
else: # not tempind
step = 0
retstatus = True
while step < num_steps:
smt.write("(declare-fun s%d () |%s_s|)" % (step, topmod))
smt.write("(assert (|%s_u| s%d))" % (topmod, step))
smt.write("(assert (|%s_h| s%d))" % (topmod, step))
smt.write("(assert %s)" % get_constr_expr(constr_assumes, step))
if step == 0:
smt.write("(assert (|%s_i| s0))" % (topmod))
smt.write("(assert (|%s_is| s0))" % (topmod))
else:
smt.write("(assert (|%s_t| s%d s%d))" % (topmod, step-1, step))
smt.write("(assert (not (|%s_is| s%d)))" % (topmod, step))
if step < skip_steps:
if assume_skipped is not None and step >= assume_skipped:
print_msg("Skipping step %d (and assuming pass).." % (step))
smt.write("(assert (|%s_a| s%d))" % (topmod, step))
smt.write("(assert %s)" % get_constr_expr(constr_asserts, step))
else:
print_msg("Skipping step %d.." % (step))
step += 1
continue
last_check_step = step
for i in range(1, step_size):
if step+i < num_steps:
smt.write("(declare-fun s%d () |%s_s|)" % (step+i, topmod))
smt.write("(assert (|%s_u| s%d))" % (topmod, step+i))
smt.write("(assert (|%s_h| s%d))" % (topmod, step+i))
smt.write("(assert (|%s_t| s%d s%d))" % (topmod, step+i-1, step+i))
smt.write("(assert %s)" % get_constr_expr(constr_assumes, step+i))
last_check_step = step+i
if not gentrace:
if not final_only:
if last_check_step == step:
print_msg("Checking asserts in step %d.." % (step))
else:
print_msg("Checking asserts in steps %d to %d.." % (step, last_check_step))
smt.write("(push 1)")
smt.write("(assert (not (and %s)))" % " ".join(["(|%s_a| s%d)" % (topmod, i) for i in range(step, last_check_step+1)] +
[get_constr_expr(constr_asserts, i) for i in range(step, last_check_step+1)]))
if smt.check_sat() == "sat":
print("%s BMC failed!" % smt.timestamp())
print_anyconsts(step)
for i in range(step, last_check_step+1):
print_failed_asserts(i)
write_trace(0, last_check_step+1, '%')
retstatus = False
break
smt.write("(pop 1)")
if (constr_final_start is not None) or (last_check_step+1 != num_steps):
for i in range(step, last_check_step+1):
smt.write("(assert (|%s_a| s%d))" % (topmod, i))
smt.write("(assert %s)" % get_constr_expr(constr_asserts, i))
if constr_final_start is not None:
for i in range(step, last_check_step+1):
if i < constr_final_start:
continue
print_msg("Checking final constraints in step %d.." % (i))
smt.write("(push 1)")
smt.write("(assert %s)" % get_constr_expr(constr_assumes, i, final=True))
smt.write("(assert (not %s))" % get_constr_expr(constr_asserts, i, final=True))
if smt.check_sat() == "sat":
print("%s BMC failed!" % smt.timestamp())
print_anyconsts(i)
print_failed_asserts(i, final=True)
write_trace(0, i+1, '%')
retstatus = False
break
smt.write("(pop 1)")
if not retstatus:
break
else: # gentrace
for i in range(step, last_check_step+1):
smt.write("(assert (|%s_a| s%d))" % (topmod, i))
smt.write("(assert %s)" % get_constr_expr(constr_asserts, i))
print_msg("Solving for step %d.." % (last_check_step))
if smt.check_sat() != "sat":
print("%s No solution found!" % smt.timestamp())
retstatus = False
break
elif dumpall:
print_anyconsts(0)
write_trace(0, last_check_step+1, "%d" % step)
step += step_size
if gentrace:
print_anyconsts(0)
write_trace(0, num_steps, '%')
smt.write("(exit)")
smt.wait()
print_msg("Status: %s" % ("PASSED" if retstatus else "FAILED (!)"))
sys.exit(0 if retstatus else 1)

View File

@ -0,0 +1,731 @@
#!/usr/bin/env python3
#
# yosys -- Yosys Open SYnthesis Suite
#
# Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
import sys, subprocess, re
from copy import deepcopy
from select import select
from time import time
hex_dict = {
"0": "0000", "1": "0001", "2": "0010", "3": "0011",
"4": "0100", "5": "0101", "6": "0110", "7": "0111",
"8": "1000", "9": "1001", "A": "1010", "B": "1011",
"C": "1100", "D": "1101", "E": "1110", "F": "1111",
"a": "1010", "b": "1011", "c": "1100", "d": "1101",
"e": "1110", "f": "1111"
}
class SmtModInfo:
def __init__(self):
self.inputs = set()
self.outputs = set()
self.registers = set()
self.memories = dict()
self.wires = set()
self.wsize = dict()
self.cells = dict()
self.asserts = dict()
self.anyconsts = dict()
class SmtIo:
def __init__(self, opts=None):
self.logic = None
self.logic_qf = True
self.logic_ax = True
self.logic_uf = True
self.logic_bv = True
self.produce_models = True
self.smt2cache = [list()]
self.p = None
if opts is not None:
self.logic = opts.logic
self.solver = opts.solver
self.debug_print = opts.debug_print
self.debug_file = opts.debug_file
self.dummy_file = opts.dummy_file
self.timeinfo = opts.timeinfo
self.unroll = opts.unroll
self.noincr = opts.noincr
self.info_stmts = opts.info_stmts
self.nocomments = opts.nocomments
else:
self.solver = "z3"
self.debug_print = False
self.debug_file = None
self.dummy_file = None
self.timeinfo = True
self.unroll = False
self.noincr = False
self.info_stmts = list()
self.nocomments = False
if self.solver == "yices":
self.popen_vargs = ['yices-smt2', '--incremental']
if self.solver == "z3":
self.popen_vargs = ['z3', '-smt2', '-in']
if self.solver == "cvc4":
self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2']
if self.solver == "mathsat":
self.popen_vargs = ['mathsat']
if self.solver == "boolector":
self.popen_vargs = ['boolector', '--smt2', '-i']
self.unroll = True
if self.solver == "abc":
self.popen_vargs = ['yosys-abc', '-S', '%blast; &sweep -C 5000; &syn4; &cec -s -m -C 2000']
self.logic_ax = False
self.unroll = True
self.noincr = True
if self.solver == "dummy":
assert self.dummy_file is not None
self.dummy_fd = open(self.dummy_file, "r")
else:
if self.dummy_file is not None:
self.dummy_fd = open(self.dummy_file, "w")
if not self.noincr:
self.p = subprocess.Popen(self.popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if self.unroll:
self.logic_uf = False
self.unroll_idcnt = 0
self.unroll_buffer = ""
self.unroll_sorts = set()
self.unroll_objs = set()
self.unroll_decls = dict()
self.unroll_cache = dict()
self.unroll_stack = list()
self.start_time = time()
self.modinfo = dict()
self.curmod = None
self.topmod = None
self.setup_done = False
def setup(self):
assert not self.setup_done
if self.logic is None:
self.logic = ""
if self.logic_qf: self.logic += "QF_"
if self.logic_ax: self.logic += "A"
if self.logic_uf: self.logic += "UF"
if self.logic_bv: self.logic += "BV"
self.setup_done = True
if self.produce_models:
self.write("(set-option :produce-models true)")
self.write("(set-logic %s)" % self.logic)
for stmt in self.info_stmts:
self.write(stmt)
def timestamp(self):
secs = int(time() - self.start_time)
return "## %6d %3d:%02d:%02d " % (secs, secs // (60*60), (secs // 60) % 60, secs % 60)
def replace_in_stmt(self, stmt, pat, repl):
if stmt == pat:
return repl
if isinstance(stmt, list):
return [self.replace_in_stmt(s, pat, repl) for s in stmt]
return stmt
def unroll_stmt(self, stmt):
if not isinstance(stmt, list):
return stmt
stmt = [self.unroll_stmt(s) for s in stmt]
if len(stmt) >= 2 and not isinstance(stmt[0], list) and stmt[0] in self.unroll_decls:
assert stmt[1] in self.unroll_objs
key = tuple(stmt)
if key not in self.unroll_cache:
decl = deepcopy(self.unroll_decls[key[0]])
self.unroll_cache[key] = "|UNROLL#%d|" % self.unroll_idcnt
decl[1] = self.unroll_cache[key]
self.unroll_idcnt += 1
if decl[0] == "declare-fun":
if isinstance(decl[3], list) or decl[3] not in self.unroll_sorts:
self.unroll_objs.add(decl[1])
decl[2] = list()
else:
self.unroll_objs.add(decl[1])
decl = list()
elif decl[0] == "define-fun":
arg_index = 1
for arg_name, arg_sort in decl[2]:
decl[4] = self.replace_in_stmt(decl[4], arg_name, key[arg_index])
arg_index += 1
decl[2] = list()
if len(decl) > 0:
decl = self.unroll_stmt(decl)
self.write(self.unparse(decl), unroll=False)
return self.unroll_cache[key]
return stmt
def write(self, stmt, unroll=True):
if stmt.startswith(";"):
self.info(stmt)
elif not self.setup_done:
self.setup()
stmt = stmt.strip()
if self.nocomments or self.unroll:
if stmt.startswith(";"):
return
stmt = re.sub(r" ;.*", "", stmt)
if unroll and self.unroll:
stmt = self.unroll_buffer + stmt
self.unroll_buffer = ""
s = re.sub(r"\|[^|]*\|", "", stmt)
if s.count("(") != s.count(")"):
self.unroll_buffer = stmt + " "
return
s = self.parse(stmt)
if self.debug_print:
print("-> %s" % s)
if len(s) == 3 and s[0] == "declare-sort" and s[2] == "0":
self.unroll_sorts.add(s[1])
return
elif len(s) == 4 and s[0] == "declare-fun" and s[2] == [] and s[3] in self.unroll_sorts:
self.unroll_objs.add(s[1])
return
elif len(s) >= 4 and s[0] == "declare-fun":
for arg_sort in s[2]:
if arg_sort in self.unroll_sorts:
self.unroll_decls[s[1]] = s
return
elif len(s) >= 4 and s[0] == "define-fun":
for arg_name, arg_sort in s[2]:
if arg_sort in self.unroll_sorts:
self.unroll_decls[s[1]] = s
return
stmt = self.unparse(self.unroll_stmt(s))
if stmt == "(push 1)":
self.unroll_stack.append((
deepcopy(self.unroll_sorts),
deepcopy(self.unroll_objs),
deepcopy(self.unroll_decls),
deepcopy(self.unroll_cache),
))
if stmt == "(pop 1)":
self.unroll_sorts, self.unroll_objs, self.unroll_decls, self.unroll_cache = self.unroll_stack.pop()
if self.debug_print:
print("> %s" % stmt)
if self.debug_file:
print(stmt, file=self.debug_file)
self.debug_file.flush()
if self.solver != "dummy":
if self.noincr:
if self.p is not None and not stmt.startswith("(get-"):
self.p.stdin.close()
self.p = None
if stmt == "(push 1)":
self.smt2cache.append(list())
elif stmt == "(pop 1)":
self.smt2cache.pop()
else:
if self.p is not None:
self.p.stdin.write(bytes(stmt + "\n", "ascii"))
self.p.stdin.flush()
self.smt2cache[-1].append(stmt)
else:
self.p.stdin.write(bytes(stmt + "\n", "ascii"))
self.p.stdin.flush()
def info(self, stmt):
if not stmt.startswith("; yosys-smt2-"):
return
fields = stmt.split()
if fields[1] == "yosys-smt2-nomem":
if self.logic is None:
self.logic_ax = False
if fields[1] == "yosys-smt2-nobv":
if self.logic is None:
self.logic_bv = False
if fields[1] == "yosys-smt2-module":
self.curmod = fields[2]
self.modinfo[self.curmod] = SmtModInfo()
if fields[1] == "yosys-smt2-cell":
self.modinfo[self.curmod].cells[fields[3]] = fields[2]
if fields[1] == "yosys-smt2-topmod":
self.topmod = fields[2]
if fields[1] == "yosys-smt2-input":
self.modinfo[self.curmod].inputs.add(fields[2])
self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3])
if fields[1] == "yosys-smt2-output":
self.modinfo[self.curmod].outputs.add(fields[2])
self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3])
if fields[1] == "yosys-smt2-register":
self.modinfo[self.curmod].registers.add(fields[2])
self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3])
if fields[1] == "yosys-smt2-memory":
self.modinfo[self.curmod].memories[fields[2]] = (int(fields[3]), int(fields[4]), int(fields[5]))
if fields[1] == "yosys-smt2-wire":
self.modinfo[self.curmod].wires.add(fields[2])
self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3])
if fields[1] == "yosys-smt2-assert":
self.modinfo[self.curmod].asserts[fields[2]] = fields[3]
if fields[1] == "yosys-smt2-anyconst":
self.modinfo[self.curmod].anyconsts[fields[2]] = fields[3]
def hiernets(self, top, regs_only=False):
def hiernets_worker(nets, mod, cursor):
for netname in sorted(self.modinfo[mod].wsize.keys()):
if not regs_only or netname in self.modinfo[mod].registers:
nets.append(cursor + [netname])
for cellname, celltype in sorted(self.modinfo[mod].cells.items()):
hiernets_worker(nets, celltype, cursor + [cellname])
nets = list()
hiernets_worker(nets, top, [])
return nets
def hiermems(self, top):
def hiermems_worker(mems, mod, cursor):
for memname in sorted(self.modinfo[mod].memories.keys()):
mems.append(cursor + [memname])
for cellname, celltype in sorted(self.modinfo[mod].cells.items()):
hiermems_worker(mems, celltype, cursor + [cellname])
mems = list()
hiermems_worker(mems, top, [])
return mems
def read(self):
stmt = []
count_brackets = 0
while True:
if self.solver == "dummy":
line = self.dummy_fd.readline().strip()
else:
line = self.p.stdout.readline().decode("ascii").strip()
if self.dummy_file is not None:
self.dummy_fd.write(line + "\n")
count_brackets += line.count("(")
count_brackets -= line.count(")")
stmt.append(line)
if self.debug_print:
print("< %s" % line)
if count_brackets == 0:
break
if self.solver != "dummy" and self.p.poll():
print("SMT Solver terminated unexpectedly: %s" % "".join(stmt))
sys.exit(1)
stmt = "".join(stmt)
if stmt.startswith("(error"):
print("SMT Solver Error: %s" % stmt, file=sys.stderr)
sys.exit(1)
return stmt
def check_sat(self):
if self.debug_print:
print("> (check-sat)")
if self.debug_file and not self.nocomments:
print("; running check-sat..", file=self.debug_file)
self.debug_file.flush()
if self.solver != "dummy":
if self.noincr:
if self.p is not None:
self.p.stdin.close()
self.p = None
self.p = subprocess.Popen(self.popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for cache_ctx in self.smt2cache:
for cache_stmt in cache_ctx:
self.p.stdin.write(bytes(cache_stmt + "\n", "ascii"))
self.p.stdin.write(bytes("(check-sat)\n", "ascii"))
self.p.stdin.flush()
if self.timeinfo:
i = 0
s = "/-\|"
count = 0
num_bs = 0
while select([self.p.stdout], [], [], 0.1) == ([], [], []):
count += 1
if count < 25:
continue
if count % 10 == 0 or count == 25:
secs = count // 10
if secs < 60:
m = "(%d seconds)" % secs
elif secs < 60*60:
m = "(%d seconds -- %d:%02d)" % (secs, secs // 60, secs % 60)
else:
m = "(%d seconds -- %d:%02d:%02d)" % (secs, secs // (60*60), (secs // 60) % 60, secs % 60)
print("%s %s %c" % ("\b \b" * num_bs, m, s[i]), end="", file=sys.stderr)
num_bs = len(m) + 3
else:
print("\b" + s[i], end="", file=sys.stderr)
sys.stderr.flush()
i = (i + 1) % len(s)
if num_bs != 0:
print("\b \b" * num_bs, end="", file=sys.stderr)
sys.stderr.flush()
result = self.read()
if self.debug_file:
print("(set-info :status %s)" % result, file=self.debug_file)
print("(check-sat)", file=self.debug_file)
self.debug_file.flush()
return result
def parse(self, stmt):
def worker(stmt):
if stmt[0] == '(':
expr = []
cursor = 1
while stmt[cursor] != ')':
el, le = worker(stmt[cursor:])
expr.append(el)
cursor += le
return expr, cursor+1
if stmt[0] == '|':
expr = "|"
cursor = 1
while stmt[cursor] != '|':
expr += stmt[cursor]
cursor += 1
expr += "|"
return expr, cursor+1
if stmt[0] in [" ", "\t", "\r", "\n"]:
el, le = worker(stmt[1:])
return el, le+1
expr = ""
cursor = 0
while stmt[cursor] not in ["(", ")", "|", " ", "\t", "\r", "\n"]:
expr += stmt[cursor]
cursor += 1
return expr, cursor
return worker(stmt)[0]
def unparse(self, stmt):
if isinstance(stmt, list):
return "(" + " ".join([self.unparse(s) for s in stmt]) + ")"
return stmt
def bv2hex(self, v):
h = ""
v = self.bv2bin(v)
while len(v) > 0:
d = 0
if len(v) > 0 and v[-1] == "1": d += 1
if len(v) > 1 and v[-2] == "1": d += 2
if len(v) > 2 and v[-3] == "1": d += 4
if len(v) > 3 and v[-4] == "1": d += 8
h = hex(d)[2:] + h
if len(v) < 4: break
v = v[:-4]
return h
def bv2bin(self, v):
if v == "true": return "1"
if v == "false": return "0"
if v.startswith("#b"):
return v[2:]
if v.startswith("#x"):
return "".join(hex_dict.get(x) for x in v[2:])
assert False
def bv2int(self, v):
return int(self.bv2bin(v), 2)
def get(self, expr):
self.write("(get-value (%s))" % (expr))
return self.parse(self.read())[0][1]
def get_list(self, expr_list):
if len(expr_list) == 0:
return []
self.write("(get-value (%s))" % " ".join(expr_list))
return [n[1] for n in self.parse(self.read())]
def get_path(self, mod, path):
assert mod in self.modinfo
path = path.split(".")
for i in range(len(path)-1):
first = ".".join(path[0:i+1])
second = ".".join(path[i+1:])
if first in self.modinfo[mod].cells:
nextmod = self.modinfo[mod].cells[first]
return [first] + self.get_path(nextmod, second)
return [".".join(path)]
def net_expr(self, mod, base, path):
if len(path) == 1:
assert mod in self.modinfo
if path[0] == "":
return base
if path[0] in self.modinfo[mod].cells:
return "(|%s_h %s| %s)" % (mod, path[0], base)
if path[0] in self.modinfo[mod].wsize:
return "(|%s_n %s| %s)" % (mod, path[0], base)
if path[0] in self.modinfo[mod].memories:
return "(|%s_m %s| %s)" % (mod, path[0], base)
assert 0
assert mod in self.modinfo
assert path[0] in self.modinfo[mod].cells
nextmod = self.modinfo[mod].cells[path[0]]
nextbase = "(|%s_h %s| %s)" % (mod, path[0], base)
return self.net_expr(nextmod, nextbase, path[1:])
def net_width(self, mod, net_path):
for i in range(len(net_path)-1):
assert mod in self.modinfo
assert net_path[i] in self.modinfo[mod].cells
mod = self.modinfo[mod].cells[net_path[i]]
assert mod in self.modinfo
assert net_path[-1] in self.modinfo[mod].wsize
return self.modinfo[mod].wsize[net_path[-1]]
def mem_expr(self, mod, base, path, portidx=None, infomode=False):
if len(path) == 1:
assert mod in self.modinfo
assert path[0] in self.modinfo[mod].memories
if infomode:
return self.modinfo[mod].memories[path[0]]
return "(|%s_m%s %s| %s)" % (mod, "" if portidx is None else ":%d" % portidx, path[0], base)
assert mod in self.modinfo
assert path[0] in self.modinfo[mod].cells
nextmod = self.modinfo[mod].cells[path[0]]
nextbase = "(|%s_h %s| %s)" % (mod, path[0], base)
return self.mem_expr(nextmod, nextbase, path[1:], portidx=portidx, infomode=infomode)
def mem_info(self, mod, base, path):
return self.mem_expr(mod, base, path, infomode=True)
def get_net(self, mod_name, net_path, state_name):
return self.get(self.net_expr(mod_name, state_name, net_path))
def get_net_list(self, mod_name, net_path_list, state_name):
return self.get_list([self.net_expr(mod_name, state_name, n) for n in net_path_list])
def get_net_hex(self, mod_name, net_path, state_name):
return self.bv2hex(self.get_net(mod_name, net_path, state_name))
def get_net_hex_list(self, mod_name, net_path_list, state_name):
return [self.bv2hex(v) for v in self.get_net_list(mod_name, net_path_list, state_name)]
def get_net_bin(self, mod_name, net_path, state_name):
return self.bv2bin(self.get_net(mod_name, net_path, state_name))
def get_net_bin_list(self, mod_name, net_path_list, state_name):
return [self.bv2bin(v) for v in self.get_net_list(mod_name, net_path_list, state_name)]
def wait(self):
if self.p is not None:
self.p.wait()
class SmtOpts:
def __init__(self):
self.shortopts = "s:v"
self.longopts = ["unroll", "noincr", "noprogress", "dump-smt2=", "logic=", "dummy=", "info=", "nocomments"]
self.solver = "z3"
self.debug_print = False
self.debug_file = None
self.dummy_file = None
self.unroll = False
self.noincr = False
self.timeinfo = True
self.logic = None
self.info_stmts = list()
self.nocomments = False
def handle(self, o, a):
if o == "-s":
self.solver = a
elif o == "-v":
self.debug_print = True
elif o == "--unroll":
self.unroll = True
elif o == "--noincr":
self.noincr = True
elif o == "--noprogress":
self.timeinfo = True
elif o == "--dump-smt2":
self.debug_file = open(a, "w")
elif o == "--logic":
self.logic = a
elif o == "--dummy":
self.dummy_file = a
elif o == "--info":
self.info_stmts.append(a)
elif o == "--nocomments":
self.nocomments = True
else:
return False
return True
def helpmsg(self):
return """
-s <solver>
set SMT solver: z3, cvc4, yices, mathsat, boolector, dummy
default: z3
--logic <smt2_logic>
use the specified SMT2 logic (e.g. QF_AUFBV)
--dummy <filename>
if solver is "dummy", read solver output from that file
otherwise: write solver output to that file
-v
enable debug output
--unroll
unroll uninterpreted functions
--noincr
don't use incremental solving, instead restart solver for
each (check-sat). This also avoids (push) and (pop).
--noprogress
disable timer display during solving
--dump-smt2 <filename>
write smt2 statements to file
--info <smt2-info-stmt>
include the specified smt2 info statement in the smt2 output
--nocomments
strip all comments from the generated smt2 code
"""
class MkVcd:
def __init__(self, f):
self.f = f
self.t = -1
self.nets = dict()
def add_net(self, path, width):
path = tuple(path)
assert self.t == -1
key = "n%d" % len(self.nets)
self.nets[path] = (key, width)
def set_net(self, path, bits):
path = tuple(path)
assert self.t >= 0
assert path in self.nets
print("b%s %s" % (bits, self.nets[path][0]), file=self.f)
def set_time(self, t):
assert t >= self.t
if t != self.t:
if self.t == -1:
print("$var integer 32 t smt_step $end", file=self.f)
print("$var event 1 ! smt_clock $end", file=self.f)
scope = []
for path in sorted(self.nets):
while len(scope)+1 > len(path) or (len(scope) > 0 and scope[-1] != path[len(scope)-1]):
print("$upscope $end", file=self.f)
scope = scope[:-1]
while len(scope)+1 < len(path):
print("$scope module %s $end" % path[len(scope)], file=self.f)
scope.append(path[len(scope)-1])
key, width = self.nets[path]
print("$var wire %d %s %s $end" % (width, key, path[-1]), file=self.f)
for i in range(len(scope)):
print("$upscope $end", file=self.f)
print("$enddefinitions $end", file=self.f)
self.t = t
assert self.t >= 0
print("#%d" % (10 * self.t), file=self.f)
print("1!", file=self.f)
print("b%s t" % format(self.t, "032b"), file=self.f)

View File

@ -0,0 +1,55 @@
#!/bin/bash
set -ex
rm -rf test_cells
mkdir test_cells
cd test_cells
../../../yosys -p 'test_cell -muxdiv -w test all /$alu /$macc /$fa /$lcu /$lut /$shift /$shiftx'
cat > miter.tpl <<- EOT
; #model# (set-option :produce-models true)
(set-logic QF_UFBV)
%%
(declare-fun s () miter_s)
(assert (|miter_n trigger| s))
(check-sat)
; #model# (get-value ((|miter_n in_A| s) (|miter_n in_B| s) (|miter_n gold_Y| s) (|miter_n gate_Y| s) (|miter_n trigger| s)))
EOT
for x in $(set +x; ls test_*.il | sort -R); do
x=${x%.il}
cat > $x.ys <<- EOT
read_ilang $x.il
copy gold gate
cd gate
techmap; opt; abc;;
cd ..
miter -equiv -flatten -make_outputs gold gate miter
hierarchy -check -top miter
dump
write_smt2 -bv -tpl miter.tpl $x.smt2
EOT
../../../yosys -q $x.ys
if ! cvc4 $x.smt2 > $x.result; then
cat $x.result
exit 1
fi
if ! grep unsat $x.result; then
echo "Proof failed! Extracting model..."
sed -i 's/^; #model# //' $x.smt2
cvc4 $x.smt2
exit 1
fi
done
set +x
echo ""
echo " All tests passed."
echo ""
exit 0

View File

@ -0,0 +1,3 @@
OBJS += backends/smv/smv.o

784
yosys/backends/smv/smv.cc Normal file
View File

@ -0,0 +1,784 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct SmvWorker
{
CellTypes ct;
SigMap sigmap;
RTLIL::Module *module;
std::ostream &f;
bool verbose;
int idcounter;
dict<IdString, shared_str> idcache;
pool<shared_str> used_names;
vector<shared_str> strbuf;
pool<Wire*> partial_assignment_wires;
dict<SigBit, std::pair<const char*, int>> partial_assignment_bits;
vector<string> assignments, invarspecs;
const char *cid()
{
while (true) {
shared_str s(stringf("_%d", idcounter++));
if (!used_names.count(s)) {
used_names.insert(s);
return s.c_str();
}
}
}
const char *cid(IdString id, bool precache = false)
{
if (!idcache.count(id))
{
string name = stringf("_%s", id.c_str());
if (name.substr(0, 2) == "_\\")
name = "_" + name.substr(2);
for (auto &c : name) {
if (c == '|' || c == '$' || c == '_') continue;
if (c >= 'a' && c <='z') continue;
if (c >= 'A' && c <='Z') continue;
if (c >= '0' && c <='9') continue;
if (precache) return nullptr;
c = '#';
}
if (name == "_main")
name = "main";
while (used_names.count(name))
name += "_";
shared_str s(name);
used_names.insert(s);
idcache[id] = s;
}
return idcache.at(id).c_str();
}
SmvWorker(RTLIL::Module *module, bool verbose, std::ostream &f) :
ct(module->design), sigmap(module), module(module), f(f), verbose(verbose), idcounter(0)
{
for (auto mod : module->design->modules())
cid(mod->name, true);
for (auto wire : module->wires())
cid(wire->name, true);
for (auto cell : module->cells()) {
cid(cell->name, true);
cid(cell->type, true);
for (auto &conn : cell->connections())
cid(conn.first, true);
}
}
const char *rvalue(SigSpec sig, int width = -1, bool is_signed = false)
{
string s;
int count_chunks = 0;
sigmap.apply(sig);
for (int i = 0; i < GetSize(sig); i++)
if (partial_assignment_bits.count(sig[i]))
{
int width = 1;
const auto &bit_a = partial_assignment_bits.at(sig[i]);
while (i+width < GetSize(sig))
{
if (!partial_assignment_bits.count(sig[i+width]))
break;
const auto &bit_b = partial_assignment_bits.at(sig[i+width]);
if (strcmp(bit_a.first, bit_b.first))
break;
if (bit_a.second+width != bit_b.second)
break;
width++;
}
if (i+width < GetSize(sig))
s = stringf("%s :: ", rvalue(sig.extract(i+width, GetSize(sig)-(width+i))));
s += stringf("%s[%d:%d]", bit_a.first, bit_a.second+width-1, bit_a.second);
if (i > 0)
s += stringf(" :: %s", rvalue(sig.extract(0, i)));
count_chunks = 3;
goto continue_with_resize;
}
for (auto &c : sig.chunks()) {
count_chunks++;
if (!s.empty())
s = " :: " + s;
if (c.wire) {
if (c.offset != 0 || c.width != c.wire->width)
s = stringf("%s[%d:%d]", cid(c.wire->name), c.offset+c.width-1, c.offset) + s;
else
s = cid(c.wire->name) + s;
} else {
string v = stringf("0ub%d_", c.width);
for (int i = c.width-1; i >= 0; i--)
v += c.data.at(i) == State::S1 ? '1' : '0';
s = v + s;
}
}
continue_with_resize:;
if (width >= 0) {
if (is_signed) {
if (GetSize(sig) > width)
s = stringf("signed(resize(%s, %d))", s.c_str(), width);
else
s = stringf("resize(signed(%s), %d)", s.c_str(), width);
} else
s = stringf("resize(%s, %d)", s.c_str(), width);
} else if (is_signed)
s = stringf("signed(%s)", s.c_str());
else if (count_chunks > 1)
s = stringf("(%s)", s.c_str());
strbuf.push_back(s);
return strbuf.back().c_str();
}
const char *rvalue_u(SigSpec sig, int width = -1)
{
return rvalue(sig, width, false);
}
const char *rvalue_s(SigSpec sig, int width = -1, bool is_signed = true)
{
return rvalue(sig, width, is_signed);
}
const char *lvalue(SigSpec sig)
{
sigmap.apply(sig);
if (sig.is_wire())
return rvalue(sig);
const char *temp_id = cid();
f << stringf(" %s : unsigned word[%d]; -- %s\n", temp_id, GetSize(sig), log_signal(sig));
int offset = 0;
for (auto bit : sig) {
log_assert(bit.wire != nullptr);
partial_assignment_wires.insert(bit.wire);
partial_assignment_bits[bit] = std::pair<const char*, int>(temp_id, offset++);
}
return temp_id;
}
void run()
{
f << stringf("MODULE %s\n", cid(module->name));
f << stringf(" VAR\n");
for (auto wire : module->wires())
{
if (SigSpec(wire) != sigmap(wire))
partial_assignment_wires.insert(wire);
f << stringf(" %s : unsigned word[%d]; -- %s\n", cid(wire->name), wire->width, log_id(wire));
if (wire->attributes.count("\\init"))
assignments.push_back(stringf("init(%s) := %s;", lvalue(wire), rvalue(wire->attributes.at("\\init"))));
}
for (auto cell : module->cells())
{
// FIXME: $slice, $concat, $mem
if (cell->type.in("$assert"))
{
SigSpec sig_a = cell->getPort("\\A");
SigSpec sig_en = cell->getPort("\\EN");
invarspecs.push_back(stringf("!bool(%s) | bool(%s);", rvalue(sig_en), rvalue(sig_a)));
continue;
}
if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx"))
{
SigSpec sig_a = cell->getPort("\\A");
SigSpec sig_b = cell->getPort("\\B");
int width_y = GetSize(cell->getPort("\\Y"));
int shift_b_width = GetSize(sig_b);
int width_ay = max(GetSize(sig_a), width_y);
int width = width_ay;
for (int i = 1, j = 0;; i <<= 1, j++)
if (width_ay < i) {
width = i-1;
shift_b_width = min(shift_b_width, j);
break;
}
bool signed_a = cell->getParam("\\A_SIGNED").as_bool();
bool signed_b = cell->getParam("\\B_SIGNED").as_bool();
string op = cell->type.in("$shl", "$sshl") ? "<<" : ">>";
string expr, expr_a;
if (cell->type == "$sshr" && signed_a)
{
expr_a = rvalue_s(sig_a, width);
expr = stringf("resize(unsigned(%s %s %s), %d)", expr_a.c_str(), op.c_str(), rvalue(sig_b.extract(0, shift_b_width)), width_y);
if (shift_b_width < GetSize(sig_b))
expr = stringf("%s != 0ud%d_0 ? (bool(%s) ? !0ud%d_0 : 0ud%d_0) : %s",
rvalue(sig_b.extract(shift_b_width, GetSize(sig_b) - shift_b_width)), GetSize(sig_b) - shift_b_width,
rvalue(sig_a[GetSize(sig_a)-1]), width_y, width_y, expr.c_str());
}
else if (cell->type.in("$shift", "$shiftx") && signed_b)
{
expr_a = rvalue_u(sig_a, width);
const char *b_shr = rvalue_u(sig_b);
const char *b_shl = cid();
f << stringf(" %s : unsigned word[%d]; -- neg(%s)\n", b_shl, GetSize(sig_b), log_signal(sig_b));
assignments.push_back(stringf("%s := unsigned(-%s);", b_shl, rvalue_s(sig_b)));
string expr_shl = stringf("resize(%s << %s[%d:0], %d)", expr_a.c_str(), b_shl, shift_b_width-1, width_y);
string expr_shr = stringf("resize(%s >> %s[%d:0], %d)", expr_a.c_str(), b_shr, shift_b_width-1, width_y);
if (shift_b_width < GetSize(sig_b)) {
expr_shl = stringf("%s[%d:%d] != 0ud%d_0 ? 0ud%d_0 : %s", b_shl, GetSize(sig_b)-1, shift_b_width,
GetSize(sig_b)-shift_b_width, width_y, expr_shl.c_str());
expr_shr = stringf("%s[%d:%d] != 0ud%d_0 ? 0ud%d_0 : %s", b_shr, GetSize(sig_b)-1, shift_b_width,
GetSize(sig_b)-shift_b_width, width_y, expr_shr.c_str());
}
expr = stringf("bool(%s) ? %s : %s", rvalue(sig_b[GetSize(sig_b)-1]), expr_shl.c_str(), expr_shr.c_str());
}
else
{
if (cell->type.in("$shift", "$shiftx") || !signed_a)
expr_a = rvalue_u(sig_a, width);
else
expr_a = stringf("resize(unsigned(%s), %d)", rvalue_s(sig_a, width_ay), width);
expr = stringf("resize(%s %s %s[%d:0], %d)", expr_a.c_str(), op.c_str(), rvalue_u(sig_b), shift_b_width-1, width_y);
if (shift_b_width < GetSize(sig_b))
expr = stringf("%s[%d:%d] != 0ud%d_0 ? 0ud%d_0 : %s", rvalue_u(sig_b), GetSize(sig_b)-1, shift_b_width,
GetSize(sig_b)-shift_b_width, width_y, expr.c_str());
}
assignments.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str()));
continue;
}
if (cell->type.in("$not", "$pos", "$neg"))
{
int width = GetSize(cell->getPort("\\Y"));
string expr_a, op;
if (cell->type == "$not") op = "!";
if (cell->type == "$pos") op = "";
if (cell->type == "$neg") op = "-";
if (cell->getParam("\\A_SIGNED").as_bool())
{
assignments.push_back(stringf("%s := unsigned(%s%s);", lvalue(cell->getPort("\\Y")),
op.c_str(), rvalue_s(cell->getPort("\\A"), width)));
}
else
{
assignments.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")),
op.c_str(), rvalue_u(cell->getPort("\\A"), width)));
}
continue;
}
if (cell->type.in("$add", "$sub", "$mul", "$and", "$or", "$xor", "$xnor"))
{
int width = GetSize(cell->getPort("\\Y"));
string expr_a, expr_b, op;
if (cell->type == "$add") op = "+";
if (cell->type == "$sub") op = "-";
if (cell->type == "$mul") op = "*";
if (cell->type == "$and") op = "&";
if (cell->type == "$or") op = "|";
if (cell->type == "$xor") op = "xor";
if (cell->type == "$xnor") op = "xnor";
if (cell->getParam("\\A_SIGNED").as_bool())
{
assignments.push_back(stringf("%s := unsigned(%s %s %s);", lvalue(cell->getPort("\\Y")),
rvalue_s(cell->getPort("\\A"), width), op.c_str(), rvalue_s(cell->getPort("\\B"), width)));
}
else
{
assignments.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")),
rvalue_u(cell->getPort("\\A"), width), op.c_str(), rvalue_u(cell->getPort("\\B"), width)));
}
continue;
}
if (cell->type.in("$div", "$mod"))
{
int width_y = GetSize(cell->getPort("\\Y"));
int width = max(width_y, GetSize(cell->getPort("\\A")));
width = max(width, GetSize(cell->getPort("\\B")));
string expr_a, expr_b, op;
if (cell->type == "$div") op = "/";
if (cell->type == "$mod") op = "mod";
if (cell->getParam("\\A_SIGNED").as_bool())
{
assignments.push_back(stringf("%s := resize(unsigned(%s %s %s), %d);", lvalue(cell->getPort("\\Y")),
rvalue_s(cell->getPort("\\A"), width), op.c_str(), rvalue_s(cell->getPort("\\B"), width), width_y));
}
else
{
assignments.push_back(stringf("%s := resize(%s %s %s, %d);", lvalue(cell->getPort("\\Y")),
rvalue_u(cell->getPort("\\A"), width), op.c_str(), rvalue_u(cell->getPort("\\B"), width), width_y));
}
continue;
}
if (cell->type.in("$eq", "$ne", "$eqx", "$nex", "$lt", "$le", "$ge", "$gt"))
{
int width = max(GetSize(cell->getPort("\\A")), GetSize(cell->getPort("\\B")));
string expr_a, expr_b, op;
if (cell->type == "$eq") op = "=";
if (cell->type == "$ne") op = "!=";
if (cell->type == "$eqx") op = "=";
if (cell->type == "$nex") op = "!=";
if (cell->type == "$lt") op = "<";
if (cell->type == "$le") op = "<=";
if (cell->type == "$ge") op = ">=";
if (cell->type == "$gt") op = ">";
if (cell->getParam("\\A_SIGNED").as_bool())
{
expr_a = stringf("resize(signed(%s), %d)", rvalue(cell->getPort("\\A")), width);
expr_b = stringf("resize(signed(%s), %d)", rvalue(cell->getPort("\\B")), width);
}
else
{
expr_a = stringf("resize(%s, %d)", rvalue(cell->getPort("\\A")), width);
expr_b = stringf("resize(%s, %d)", rvalue(cell->getPort("\\B")), width);
}
assignments.push_back(stringf("%s := resize(word1(%s %s %s), %d);", lvalue(cell->getPort("\\Y")),
expr_a.c_str(), op.c_str(), expr_b.c_str(), GetSize(cell->getPort("\\Y"))));
continue;
}
if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool"))
{
int width_a = GetSize(cell->getPort("\\A"));
int width_y = GetSize(cell->getPort("\\Y"));
const char *expr_a = rvalue(cell->getPort("\\A"));
const char *expr_y = lvalue(cell->getPort("\\Y"));
string expr;
if (cell->type == "$reduce_and") expr = stringf("%s = !0ub%d_0", expr_a, width_a);
if (cell->type == "$reduce_or") expr = stringf("%s != 0ub%d_0", expr_a, width_a);
if (cell->type == "$reduce_bool") expr = stringf("%s != 0ub%d_0", expr_a, width_a);
assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y));
continue;
}
if (cell->type.in("$reduce_xor", "$reduce_xnor"))
{
int width_y = GetSize(cell->getPort("\\Y"));
const char *expr_y = lvalue(cell->getPort("\\Y"));
string expr;
for (auto bit : cell->getPort("\\A")) {
if (!expr.empty())
expr += " xor ";
expr += rvalue(bit);
}
if (cell->type == "$reduce_xnor")
expr = "!(" + expr + ")";
assignments.push_back(stringf("%s := resize(%s, %d);", expr_y, expr.c_str(), width_y));
continue;
}
if (cell->type.in("$logic_and", "$logic_or"))
{
int width_a = GetSize(cell->getPort("\\A"));
int width_b = GetSize(cell->getPort("\\B"));
int width_y = GetSize(cell->getPort("\\Y"));
string expr_a = stringf("(%s != 0ub%d_0)", rvalue(cell->getPort("\\A")), width_a);
string expr_b = stringf("(%s != 0ub%d_0)", rvalue(cell->getPort("\\B")), width_b);
const char *expr_y = lvalue(cell->getPort("\\Y"));
string expr;
if (cell->type == "$logic_and") expr = expr_a + " & " + expr_b;
if (cell->type == "$logic_or") expr = expr_a + " | " + expr_b;
assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y));
continue;
}
if (cell->type.in("$logic_not"))
{
int width_a = GetSize(cell->getPort("\\A"));
int width_y = GetSize(cell->getPort("\\Y"));
string expr_a = stringf("(%s = 0ub%d_0)", rvalue(cell->getPort("\\A")), width_a);
const char *expr_y = lvalue(cell->getPort("\\Y"));
assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr_a.c_str(), width_y));
continue;
}
if (cell->type.in("$mux", "$pmux"))
{
int width = GetSize(cell->getPort("\\Y"));
SigSpec sig_a = cell->getPort("\\A");
SigSpec sig_b = cell->getPort("\\B");
SigSpec sig_s = cell->getPort("\\S");
string expr;
for (int i = 0; i < GetSize(sig_s); i++)
expr += stringf("bool(%s) ? %s : ", rvalue(sig_s[i]), rvalue(sig_b.extract(i*width, width)));
expr += rvalue(sig_a);
assignments.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str()));
continue;
}
if (cell->type == "$dff")
{
assignments.push_back(stringf("next(%s) := %s;", lvalue(cell->getPort("\\Q")), rvalue(cell->getPort("\\D"))));
continue;
}
if (cell->type.in("$_BUF_", "$_NOT_"))
{
string op = cell->type == "$_NOT_" ? "!" : "";
assignments.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")), op.c_str(), rvalue(cell->getPort("\\A"))));
continue;
}
if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
{
string op;
if (cell->type.in("$_AND_", "$_NAND_")) op = "&";
if (cell->type.in("$_OR_", "$_NOR_")) op = "|";
if (cell->type.in("$_XOR_")) op = "xor";
if (cell->type.in("$_XNOR_")) op = "xnor";
if (cell->type.in("$_NAND_", "$_NOR_"))
assignments.push_back(stringf("%s := !(%s %s %s);", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
else
assignments.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
continue;
}
if (cell->type == "$_MUX_")
{
assignments.push_back(stringf("%s := bool(%s) ? %s : %s;", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\S")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\A"))));
continue;
}
if (cell->type == "$_AOI3_")
{
assignments.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C"))));
continue;
}
if (cell->type == "$_OAI3_")
{
assignments.push_back(stringf("%s := !((%s | %s) & %s);", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C"))));
continue;
}
if (cell->type == "$_AOI4_")
{
assignments.push_back(stringf("%s := !((%s & %s) | (%s & %s));", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")), rvalue(cell->getPort("\\D"))));
continue;
}
if (cell->type == "$_OAI4_")
{
assignments.push_back(stringf("%s := !((%s | %s) & (%s | %s));", lvalue(cell->getPort("\\Y")),
rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")), rvalue(cell->getPort("\\D"))));
continue;
}
if (cell->type[0] == '$')
log_error("Found currently unsupported cell type %s (%s.%s).\n", log_id(cell->type), log_id(module), log_id(cell));
f << stringf(" %s : %s;\n", cid(cell->name), cid(cell->type));
for (auto &conn : cell->connections())
if (cell->output(conn.first))
assignments.push_back(stringf("%s := %s.%s;", lvalue(conn.second), cid(cell->name), cid(conn.first)));
else
assignments.push_back(stringf("%s.%s := %s;", cid(cell->name), cid(conn.first), rvalue(conn.second)));
}
for (Wire *wire : partial_assignment_wires)
{
string expr;
for (int i = 0; i < wire->width; i++)
{
if (!expr.empty())
expr = " :: " + expr;
if (partial_assignment_bits.count(sigmap(SigBit(wire, i))))
{
int width = 1;
const auto &bit_a = partial_assignment_bits.at(sigmap(SigBit(wire, i)));
while (i+1 < wire->width)
{
SigBit next_bit = sigmap(SigBit(wire, i+1));
if (!partial_assignment_bits.count(next_bit))
break;
const auto &bit_b = partial_assignment_bits.at(next_bit);
if (strcmp(bit_a.first, bit_b.first))
break;
if (bit_a.second+width != bit_b.second)
break;
width++, i++;
}
expr = stringf("%s[%d:%d]", bit_a.first, bit_a.second+width-1, bit_a.second) + expr;
}
else if (sigmap(SigBit(wire, i)).wire == nullptr)
{
string bits;
SigSpec sig = sigmap(SigSpec(wire, i));
while (i+1 < wire->width) {
SigBit next_bit = sigmap(SigBit(wire, i+1));
if (next_bit.wire != nullptr)
break;
sig.append(next_bit);
i++;
}
for (int k = GetSize(sig)-1; k >= 0; k--)
bits += sig[k] == State::S1 ? '1' : '0';
expr = stringf("0ub%d_%s", GetSize(bits), bits.c_str()) + expr;
}
else if (sigmap(SigBit(wire, i)) == SigBit(wire, i))
{
int length = 1;
while (i+1 < wire->width) {
if (partial_assignment_bits.count(sigmap(SigBit(wire, i+1))))
break;
if (sigmap(SigBit(wire, i+1)) != SigBit(wire, i+1))
break;
i++, length++;
}
expr = stringf("0ub%d_0", length) + expr;
}
else
{
string bits;
SigSpec sig = sigmap(SigSpec(wire, i));
while (i+1 < wire->width) {
SigBit next_bit = sigmap(SigBit(wire, i+1));
if (next_bit.wire == nullptr || partial_assignment_bits.count(next_bit))
break;
sig.append(next_bit);
i++;
}
expr = rvalue(sig) + expr;
}
}
assignments.push_back(stringf("%s := %s;", cid(wire->name), expr.c_str()));
}
if (!assignments.empty()) {
f << stringf(" ASSIGN\n");
for (const string &line : assignments)
f << stringf(" %s\n", line.c_str());
}
if (!invarspecs.empty()) {
for (const string &line : invarspecs)
f << stringf(" INVARSPEC %s\n", line.c_str());
}
}
};
struct SmvBackend : public Backend {
SmvBackend() : Backend("smv", "write design to SMV file") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" write_smv [options] [filename]\n");
log("\n");
log("Write an SMV description of the current design.\n");
log("\n");
log(" -verbose\n");
log(" this will print the recursive walk used to export the modules.\n");
log("\n");
log(" -tpl <template_file>\n");
log(" use the given template file. the line containing only the token '%%%%'\n");
log(" is replaced with the regular output of this command.\n");
log("\n");
log("THIS COMMAND IS UNDER CONSTRUCTION\n");
log("\n");
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
std::ifstream template_f;
bool verbose = false;
log_header(design, "Executing SMV backend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-tpl" && argidx+1 < args.size()) {
template_f.open(args[++argidx]);
if (template_f.fail())
log_error("Can't open template file `%s'.\n", args[argidx].c_str());
continue;
}
if (args[argidx] == "-verbose") {
verbose = true;
continue;
}
break;
}
extra_args(f, filename, args, argidx);
pool<Module*> modules;
for (auto module : design->modules())
if (!module->get_bool_attribute("\\blackbox") && !module->has_memories_warn() && !module->has_processes_warn())
modules.insert(module);
if (template_f.is_open())
{
std::string line;
while (std::getline(template_f, line))
{
int indent = 0;
while (indent < GetSize(line) && (line[indent] == ' ' || line[indent] == '\t'))
indent++;
if (line[indent] == '%')
{
vector<string> stmt = split_tokens(line);
if (GetSize(stmt) == 1 && stmt[0] == "%%")
break;
if (GetSize(stmt) == 2 && stmt[0] == "%module")
{
Module *module = design->module(RTLIL::escape_id(stmt[1]));
modules.erase(module);
if (module == nullptr)
log_error("Module '%s' not found.\n", stmt[1].c_str());
*f << stringf("-- SMV description generated by %s\n", yosys_version_str);
log("Creating SMV representation of module %s.\n", log_id(module));
SmvWorker worker(module, verbose, *f);
worker.run();
*f << stringf("-- end of yosys output\n");
continue;
}
log_error("Unknown template statement: '%s'", line.c_str() + indent);
}
*f << line << std::endl;
}
}
if (!modules.empty())
{
*f << stringf("-- SMV description generated by %s\n", yosys_version_str);
for (auto module : modules) {
log("Creating SMV representation of module %s.\n", log_id(module));
SmvWorker worker(module, verbose, *f);
worker.run();
}
*f << stringf("-- end of yosys output\n");
}
if (template_f.is_open()) {
std::string line;
while (std::getline(template_f, line))
*f << line << std::endl;
}
}
} SmvBackend;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,33 @@
#!/bin/bash
set -ex
rm -rf test_cells.tmp
mkdir -p test_cells.tmp
cd test_cells.tmp
# don't test $mul to reduce runtime
# don't test $div and $mod to reduce runtime and avoid "div by zero" message
../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$macc /$mul /$div /$mod'
cat > template.txt << "EOT"
%module main
INVARSPEC ! bool(_trigger);
EOT
for fn in test_*.il; do
../../../yosys -p "
read_ilang $fn
rename gold gate
synth
read_ilang $fn
miter -equiv -flatten gold gate main
hierarchy -top main
write_smv -tpl template.txt ${fn#.il}.smv
"
nuXmv -dynamic ${fn#.il}.smv > ${fn#.il}.out
done
grep '^-- invariant .* is false' *.out || echo 'All OK.'

View File

@ -0,0 +1,3 @@
OBJS += backends/spice/spice.o

View File

@ -0,0 +1,266 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static string spice_id2str(IdString id)
{
static const char *escape_chars = "$\\[]()<>=";
string s = RTLIL::unescape_id(id);
for (auto &ch : s)
if (strchr(escape_chars, ch) != nullptr) ch = '_';
return s;
}
static string spice_id2str(IdString id, bool use_inames, idict<IdString, 1> &inums)
{
if (!use_inames && *id.c_str() == '$')
return stringf("%d", inums(id));
return spice_id2str(id);
}
static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg, std::string &pos, std::string &ncpf, int &nc_counter, bool use_inames, idict<IdString, 1> &inums)
{
if (s.wire) {
if (s.wire->port_id)
use_inames = true;
if (s.wire->width > 1)
f << stringf(" %s.%d", spice_id2str(s.wire->name, use_inames, inums).c_str(), s.offset);
else
f << stringf(" %s", spice_id2str(s.wire->name, use_inames, inums).c_str());
} else {
if (s == RTLIL::State::S0)
f << stringf(" %s", neg.c_str());
else if (s == RTLIL::State::S1)
f << stringf(" %s", pos.c_str());
else
f << stringf(" %s%d", ncpf.c_str(), nc_counter++);
}
}
static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, std::string &neg, std::string &pos, std::string &ncpf, bool big_endian, bool use_inames)
{
SigMap sigmap(module);
idict<IdString, 1> inums;
int cell_counter = 0, conn_counter = 0, nc_counter = 0;
for (auto &cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
f << stringf("X%d", cell_counter++);
std::vector<RTLIL::SigSpec> port_sigs;
if (design->modules_.count(cell->type) == 0)
{
log_warning("no (blackbox) module for cell type `%s' (%s.%s) found! Guessing order of ports.\n",
log_id(cell->type), log_id(module), log_id(cell));
for (auto &conn : cell->connections()) {
RTLIL::SigSpec sig = sigmap(conn.second);
port_sigs.push_back(sig);
}
}
else
{
RTLIL::Module *mod = design->modules_.at(cell->type);
std::vector<RTLIL::Wire*> ports;
for (auto wire_it : mod->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_id == 0)
continue;
while (int(ports.size()) < wire->port_id)
ports.push_back(NULL);
ports.at(wire->port_id-1) = wire;
}
for (RTLIL::Wire *wire : ports) {
log_assert(wire != NULL);
RTLIL::SigSpec sig(RTLIL::State::Sz, wire->width);
if (cell->hasPort(wire->name)) {
sig = sigmap(cell->getPort(wire->name));
sig.extend_u0(wire->width, false);
}
port_sigs.push_back(sig);
}
}
for (auto &sig : port_sigs) {
for (int i = 0; i < sig.size(); i++) {
RTLIL::SigSpec s = sig.extract(big_endian ? sig.size() - 1 - i : i, 1);
print_spice_net(f, s, neg, pos, ncpf, nc_counter, use_inames, inums);
}
}
f << stringf(" %s\n", spice_id2str(cell->type).c_str());
}
for (auto &conn : module->connections())
for (int i = 0; i < conn.first.size(); i++) {
f << stringf("V%d", conn_counter++);
print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums);
print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums);
f << stringf(" DC 0\n");
}
}
struct SpiceBackend : public Backend {
SpiceBackend() : Backend("spice", "write design to SPICE netlist file") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" write_spice [options] [filename]\n");
log("\n");
log("Write the current design to an SPICE netlist file.\n");
log("\n");
log(" -big_endian\n");
log(" generate multi-bit ports in MSB first order\n");
log(" (default is LSB first)\n");
log("\n");
log(" -neg net_name\n");
log(" set the net name for constant 0 (default: Vss)\n");
log("\n");
log(" -pos net_name\n");
log(" set the net name for constant 1 (default: Vdd)\n");
log("\n");
log(" -nc_prefix\n");
log(" prefix for not-connected nets (default: _NC)\n");
log("\n");
log(" -inames\n");
log(" include names of internal ($-prefixed) nets in outputs\n");
log(" (default is to use net numbers instead)\n");
log("\n");
log(" -top top_module\n");
log(" set the specified module as design top module\n");
log("\n");
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
std::string top_module_name;
RTLIL::Module *top_module = NULL;
bool big_endian = false, use_inames = false;
std::string neg = "Vss", pos = "Vdd", ncpf = "_NC";
log_header(design, "Executing SPICE backend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-big_endian") {
big_endian = true;
continue;
}
if (args[argidx] == "-inames") {
use_inames = true;
continue;
}
if (args[argidx] == "-neg" && argidx+1 < args.size()) {
neg = args[++argidx];
continue;
}
if (args[argidx] == "-pos" && argidx+1 < args.size()) {
pos = args[++argidx];
continue;
}
if (args[argidx] == "-nc_prefix" && argidx+1 < args.size()) {
ncpf = args[++argidx];
continue;
}
if (args[argidx] == "-top" && argidx+1 < args.size()) {
top_module_name = args[++argidx];
continue;
}
break;
}
extra_args(f, filename, args, argidx);
if (top_module_name.empty())
for (auto & mod_it:design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
top_module_name = mod_it.first.str();
*f << stringf("* SPICE netlist generated by %s\n", yosys_version_str);
*f << stringf("\n");
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox"))
continue;
if (module->processes.size() != 0)
log_error("Found unmapped processes in module %s: unmapped processes are not supported in SPICE backend!\n", log_id(module));
if (module->memories.size() != 0)
log_error("Found unmapped memories in module %s: unmapped memories are not supported in SPICE backend!\n", log_id(module));
if (module->name == RTLIL::escape_id(top_module_name)) {
top_module = module;
continue;
}
std::vector<RTLIL::Wire*> ports;
for (auto wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_id == 0)
continue;
while (int(ports.size()) < wire->port_id)
ports.push_back(NULL);
ports.at(wire->port_id-1) = wire;
}
*f << stringf(".SUBCKT %s", spice_id2str(module->name).c_str());
for (RTLIL::Wire *wire : ports) {
log_assert(wire != NULL);
if (wire->width > 1) {
for (int i = 0; i < wire->width; i++)
*f << stringf(" %s.%d", spice_id2str(wire->name).c_str(), big_endian ? wire->width - 1 - i : i);
} else
*f << stringf(" %s", spice_id2str(wire->name).c_str());
}
*f << stringf("\n");
print_spice_module(*f, module, design, neg, pos, ncpf, big_endian, use_inames);
*f << stringf(".ENDS %s\n\n", spice_id2str(module->name).c_str());
}
if (!top_module_name.empty()) {
if (top_module == NULL)
log_error("Can't find top module `%s'!\n", top_module_name.c_str());
print_spice_module(*f, top_module, design, neg, pos, ncpf, big_endian, use_inames);
*f << stringf("\n");
}
*f << stringf("************************\n");
*f << stringf("* end of SPICE netlist *\n");
*f << stringf("************************\n");
*f << stringf("\n");
}
} SpiceBackend;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,3 @@
OBJS += backends/verilog/verilog_backend.o

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
A simple example design, based on the Digilent BASYS3 board
===========================================================
This example uses Yosys for synthesis and Xilinx Vivado
for place&route and bit-stream creation.
Running Yosys:
yosys run_yosys.ys
Running Vivado:
vivado -nolog -nojournal -mode batch -source run_vivado.tcl
Programming board:
vivado -nolog -nojournal -mode batch -source run_prog.tcl
All of the above:
bash run.sh

View File

@ -0,0 +1,21 @@
module example(CLK, LD);
input CLK;
output [15:0] LD;
wire clock;
reg [15:0] leds;
BUFG CLK_BUF (.I(CLK), .O(clock));
OBUF LD_BUF[15:0] (.I(leds), .O(LD));
parameter COUNTBITS = 26;
reg [COUNTBITS-1:0] counter;
always @(posedge CLK) begin
counter <= counter + 1;
if (counter[COUNTBITS-1])
leds <= 16'h8000 >> counter[COUNTBITS-2:COUNTBITS-5];
else
leds <= 16'h0001 << counter[COUNTBITS-2:COUNTBITS-5];
end
endmodule

View File

@ -0,0 +1,21 @@
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN W5 } [get_ports CLK]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U16 } [get_ports {LD[0]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN E19 } [get_ports {LD[1]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U19 } [get_ports {LD[2]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V19 } [get_ports {LD[3]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN W18 } [get_ports {LD[4]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U15 } [get_ports {LD[5]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U14 } [get_ports {LD[6]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V14 } [get_ports {LD[7]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V13 } [get_ports {LD[8]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN V3 } [get_ports {LD[9]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN W3 } [get_ports {LD[10]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN U3 } [get_ports {LD[11]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN P3 } [get_ports {LD[12]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN N3 } [get_ports {LD[13]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN P1 } [get_ports {LD[14]}]
set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN L1 } [get_ports {LD[15]}]
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports CLK]

View File

@ -0,0 +1,4 @@
#!/bin/bash
yosys run_yosys.ys
vivado -nolog -nojournal -mode batch -source run_vivado.tcl
vivado -nolog -nojournal -mode batch -source run_prog.tcl

View File

@ -0,0 +1,4 @@
connect_hw_server
open_hw_target [lindex [get_hw_targets] 0]
set_property PROGRAM.FILE example.bit [lindex [get_hw_devices] 0]
program_hw_devices [lindex [get_hw_devices] 0]

View File

@ -0,0 +1,9 @@
read_xdc example.xdc
read_edif example.edif
link_design -part xc7a35tcpg236-1 -top example
opt_design
place_design
route_design
report_utilization
report_timing
write_bitstream -force example.bit

View File

@ -0,0 +1,2 @@
read_verilog example.v
synth_xilinx -edif example.edif -top example

4
yosys/examples/cmos/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
counter_tb
counter_tb.vcd
synth.sp
synth.v

View File

@ -0,0 +1,13 @@
In this directory contains an example for generating a spice output using two
different spice modes, normal analog transient simulation and event-driven
digital simulation as supported by ngspice xspice sub-module.
Each test bench can be run separately by either running:
- testbench.sh, to start analog simulation or
- testbench_digital.sh for mixed-signal digital simulation.
The later case also includes pure verilog simulation using the iverilog
and gtkwave for comparison.

View File

@ -0,0 +1,55 @@
// test comment
/* test comment */
library(demo) {
cell(BUF) {
area: 6;
pin(A) { direction: input; }
pin(Y) { direction: output;
function: "A"; }
}
cell(NOT) {
area: 3;
pin(A) { direction: input; }
pin(Y) { direction: output;
function: "A'"; }
}
cell(NAND) {
area: 4;
pin(A) { direction: input; }
pin(B) { direction: input; }
pin(Y) { direction: output;
function: "(A*B)'"; }
}
cell(NOR) {
area: 4;
pin(A) { direction: input; }
pin(B) { direction: input; }
pin(Y) { direction: output;
function: "(A+B)'"; }
}
cell(DFF) {
area: 18;
ff(IQ, IQN) { clocked_on: C;
next_state: D; }
pin(C) { direction: input;
clock: true; }
pin(D) { direction: input; }
pin(Q) { direction: output;
function: "IQ"; }
}
cell(DFFSR) {
area: 18;
ff("IQ", "IQN") { clocked_on: C;
next_state: D;
preset: S;
clear: R; }
pin(C) { direction: input;
clock: true; }
pin(D) { direction: input; }
pin(Q) { direction: output;
function: "IQ"; }
pin(S) { direction: input; }
pin(R) { direction: input; }
; // empty statement
}
}

View File

@ -0,0 +1,39 @@
.SUBCKT BUF A Y
X1 A B NOT
X2 B Y NOT
.ENDS NOT
.SUBCKT NOT A Y
M1 Y A Vdd Vdd cmosp L=1u W=10u
M2 Y A Vss Vss cmosn L=1u W=10u
.ENDS NOT
.SUBCKT NAND A B Y
M1 Y A Vdd Vdd cmosp L=1u W=10u
M2 Y B Vdd Vdd cmosp L=1u W=10u
M3 Y A M34 Vss cmosn L=1u W=10u
M4 M34 B Vss Vss cmosn L=1u W=10u
.ENDS NAND
.SUBCKT NOR A B Y
M1 Y A M12 Vdd cmosp L=1u W=10u
M2 M12 B Vdd Vdd cmosp L=1u W=10u
M3 Y A Vss Vss cmosn L=1u W=10u
M4 Y B Vss Vss cmosn L=1u W=10u
.ENDS NOR
.SUBCKT DLATCH E D Q
X1 D E S NAND
X2 nD E R NAND
X3 S nQ Q NAND
X4 Q R nQ NAND
X5 D nD NOT
.ENDS DLATCH
.SUBCKT DFF C D Q
X1 nC D t DLATCH
X2 C t Q DLATCH
X3 C nC NOT
.ENDS DFF

View File

@ -0,0 +1,44 @@
module BUF(A, Y);
input A;
output Y;
assign Y = A;
endmodule
module NOT(A, Y);
input A;
output Y;
assign Y = ~A;
endmodule
module NAND(A, B, Y);
input A, B;
output Y;
assign Y = ~(A & B);
endmodule
module NOR(A, B, Y);
input A, B;
output Y;
assign Y = ~(A | B);
endmodule
module DFF(C, D, Q);
input C, D;
output reg Q;
always @(posedge C)
Q <= D;
endmodule
module DFFSR(C, D, Q, S, R);
input C, D, S, R;
output reg Q;
always @(posedge C, posedge S, posedge R)
if (S)
Q <= 1'b1;
else if (R)
Q <= 1'b0;
else
Q <= D;
endmodule

View File

@ -0,0 +1,31 @@
.SUBCKT BUF A Y
.model buffer1 d_buffer
Abuf A Y buffer1
.ENDS NOT
.SUBCKT NOT A Y
.model not1 d_inverter
Anot A Y not1
.ENDS NOT
.SUBCKT NAND A B Y
.model nand1 d_nand
Anand [A B] Y nand1
.ENDS NAND
.SUBCKT NOR A B Y
.model nor1 d_nor
Anand [A B] Y nor1
.ENDS NOR
.SUBCKT DLATCH E D Q
.model latch1 d_latch
Alatch D E null null Q nQ latch1
.ENDS DLATCH
.SUBCKT DFF C D Q
.model dff1 d_dff
Adff D C null null Q nQ dff1
.ENDS DFF

View File

@ -0,0 +1,12 @@
module counter (clk, rst, en, count);
input clk, rst, en;
output reg [2:0] count;
always @(posedge clk)
if (rst)
count <= 3'd0;
else if (en)
count <= count + 3'd1;
endmodule

View File

@ -0,0 +1,16 @@
read_verilog counter.v
read_verilog -lib cmos_cells.v
proc;; memory;; techmap;;
dfflibmap -liberty cmos_cells.lib
abc -liberty cmos_cells.lib;;
# http://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/latest/cadence/lib/tsmc025/signalstorm/osu025_stdcells.lib
# dfflibmap -liberty osu025_stdcells.lib
# abc -liberty osu025_stdcells.lib;;
write_verilog synth.v
write_spice synth.sp

View File

@ -0,0 +1,16 @@
read_verilog counter.v
read_verilog -lib cmos_cells.v
proc;; memory;; techmap;;
dfflibmap -liberty cmos_cells.lib
abc -liberty cmos_cells.lib;;
# http://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/latest/cadence/lib/tsmc025/signalstorm/osu025_stdcells.lib
# dfflibmap -liberty osu025_stdcells.lib
# abc -liberty osu025_stdcells.lib;;
write_verilog synth.v
write_spice -neg 0s -pos 1s synth.sp

View File

@ -0,0 +1,5 @@
[dumpfile] "counter_tb.vcd"
counter_tb.clk
counter_tb.count[2:0]
counter_tb.en
counter_tb.reset

View File

@ -0,0 +1,33 @@
module counter_tb;
/* Make a reset pulse and specify dump file */
reg reset = 0;
initial begin
$dumpfile("counter_tb.vcd");
$dumpvars(0,counter_tb);
# 0 reset = 1;
# 4 reset = 0;
# 36 reset = 1;
# 4 reset = 0;
# 6 $finish;
end
/* Make enable with period of 8 and 6,7 low */
reg en = 1;
always begin
en = 1;
#6;
en = 0;
#2;
end
/* Make a regular pulsing clock. */
reg clk = 0;
always #1 clk = !clk;
/* UUT */
wire [2:0] count;
counter c1 (clk, reset, en, count);
endmodule

View File

@ -0,0 +1,7 @@
#!/bin/bash
set -ex
../../yosys counter.ys
ngspice testbench.sp

View File

@ -0,0 +1,29 @@
* supply voltages
.global Vss Vdd
Vss Vss 0 DC 0
Vdd Vdd 0 DC 3
* simple transistor model
.MODEL cmosn NMOS LEVEL=1 VT0=0.7 KP=110U GAMMA=0.4 LAMBDA=0.04 PHI=0.7
.MODEL cmosp PMOS LEVEL=1 VT0=-0.7 KP=50U GAMMA=0.57 LAMBDA=0.05 PHI=0.8
* load design and library
.include cmos_cells.sp
.include synth.sp
* input signals
Vclk clk 0 PULSE(0 3 1 0.1 0.1 0.8 2)
Vrst rst 0 PULSE(0 3 0.5 0.1 0.1 2.9 40)
Ven en 0 PULSE(0 3 0.5 0.1 0.1 5.9 8)
Xuut clk rst en out0 out1 out2 COUNTER
.tran 0.01 50
.control
run
plot v(clk) v(rst)+5 v(en)+10 v(out0)+20 v(out1)+25 v(out2)+30
.endc
.end

View File

@ -0,0 +1,15 @@
#!/bin/bash
set -ex
# iverlog simulation
echo "Doing Verilog simulation with iverilog"
iverilog -o counter_tb counter.v counter_tb.v
./counter_tb; gtkwave counter_tb.gtkw &
# yosys synthesis
../../yosys counter_digital.ys
# requires ngspice with xspice support enabled:
ngspice testbench_digital.sp

View File

@ -0,0 +1,26 @@
* load design and library
.include cmos_cells_digital.sp
.include synth.sp
* input signals
Vclk clk 0 PULSE(0 3 1 0.1 0.1 0.8 2)
Vrst rst 0 PULSE(0 3 0.5 0.1 0.1 2.9 40)
Ven en 0 PULSE(0 3 0.5 0.1 0.1 5.9 8)
Xuut dclk drst den dout0 dout1 dout2 counter
* Bridge to digital
.model adc_buff adc_bridge(in_low = 0.8 in_high=2)
.model dac_buff dac_bridge(out_high = 3.5)
Aad [clk rst en] [dclk drst den] adc_buff
Ada [dout0 dout1 dout2] [out0 out1 out2] dac_buff
.tran 0.01 50
.control
run
plot v(clk) v(rst)+5 v(en)+10 v(out0)+20 v(out1)+25 v(out2)+30
.endc
.end

View File

@ -0,0 +1,22 @@
// Note: Set ENABLE_LIBYOSYS=1 in Makefile or Makefile.conf to build libyosys.so
// yosys-config --exec --cxx -o demomain --cxxflags --ldflags demomain.cc -lyosys -lstdc++
#include <kernel/yosys.h>
int main()
{
Yosys::log_streams.push_back(&std::cout);
Yosys::log_error_stderr = true;
Yosys::yosys_setup();
Yosys::yosys_banner();
Yosys::run_pass("read_verilog example.v");
Yosys::run_pass("synth -noabc");
Yosys::run_pass("clean -purge");
Yosys::run_pass("write_blif example.blif");
Yosys::yosys_shutdown();
return 0;
}

View File

@ -0,0 +1,55 @@
/* A simple Yosys plugin. (Copy&paste from http://stackoverflow.com/questions/32093541/how-does-the-yosys-consteval-api-work)
Usage example:
$ cat > evaldemo.v <<EOT
module main(input [1:0] A, input [7:0] B, C, D, output [7:0] Y);
assign Y = A == 0 ? B : A == 1 ? C : A == 2 ? D : 42;
endmodule
EOT
$ yosys-config --build evaldemo.so evaldemo.cc
$ yosys -m evaldemo.so -p evaldemo evaldemo.v
*/
#include "kernel/yosys.h"
#include "kernel/consteval.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct EvalDemoPass : public Pass
{
EvalDemoPass() : Pass("evaldemo") { }
virtual void execute(vector<string>, Design *design)
{
Module *module = design->top_module();
if (module == nullptr)
log_error("No top module found!\n");
Wire *wire_a = module->wire("\\A");
Wire *wire_y = module->wire("\\Y");
if (wire_a == nullptr)
log_error("No wire A found!\n");
if (wire_y == nullptr)
log_error("No wire Y found!\n");
ConstEval ce(module);
for (int v = 0; v < 4; v++) {
ce.push();
ce.set(wire_a, Const(v, GetSize(wire_a)));
SigSpec sig_y = wire_y, sig_undef;
if (ce.eval(sig_y, sig_undef))
log("Eval results for A=%d: Y=%s\n", v, log_signal(sig_y));
else
log("Eval failed for A=%d: Missing value for %s\n", v, log_signal(sig_undef));
ce.pop();
}
}
} EvalDemoPass;
PRIVATE_NAMESPACE_END

22
yosys/examples/smtbmc/.gitignore vendored Normal file
View File

@ -0,0 +1,22 @@
demo1.smt2
demo1.yslog
demo2.smt2
demo2.smtc
demo2.vcd
demo2.yslog
demo2_tb
demo2_tb.v
demo2_tb.vcd
demo3.smt2
demo3.vcd
demo3.yslog
demo4.smt2
demo4.vcd
demo4.yslog
demo5.smt2
demo5.vcd
demo5.yslog
demo6.smt2
demo6.yslog
demo7.smt2
demo7.yslog

View File

@ -0,0 +1,59 @@
all: demo1 demo2 demo3 demo4 demo5 demo6 demo7
demo1: demo1.smt2
yosys-smtbmc --dump-vcd demo1.vcd demo1.smt2
yosys-smtbmc -i --dump-vcd demo1.vcd demo1.smt2
demo2: demo2.smt2
yosys-smtbmc -g --dump-vcd demo2.vcd --dump-smtc demo2.smtc --dump-vlogtb demo2_tb.v demo2.smt2
iverilog -g2012 -o demo2_tb demo2_tb.v demo2.v
vvp demo2_tb +vcd=demo2_tb.vcd
demo3: demo3.smt2
yosys-smtbmc --dump-vcd demo3.vcd --smtc demo3.smtc demo3.smt2
demo4: demo4.smt2
yosys-smtbmc -s yices --dump-vcd demo4.vcd --smtc demo4.smtc demo4.smt2
demo5: demo5.smt2
yosys-smtbmc -g -t 50 --dump-vcd demo5.vcd demo5.smt2
demo6: demo6.smt2
yosys-smtbmc -t 1 demo6.smt2
demo7: demo7.smt2
yosys-smtbmc -t 10 demo7.smt2
demo1.smt2: demo1.v
yosys -ql demo1.yslog -p 'read_verilog -formal demo1.v; prep -top demo1 -nordff; write_smt2 -wires demo1.smt2'
demo2.smt2: demo2.v
yosys -ql demo2.yslog -p 'read_verilog -formal demo2.v; prep -top demo2 -nordff; write_smt2 -wires demo2.smt2'
demo3.smt2: demo3.v
yosys -ql demo3.yslog -p 'read_verilog -formal demo3.v; prep -top demo3 -nordff; write_smt2 -wires demo3.smt2'
demo4.smt2: demo4.v
yosys -ql demo4.yslog -p 'read_verilog -formal demo4.v; prep -top demo4 -nordff; write_smt2 -wires demo4.smt2'
demo5.smt2: demo5.v
yosys -ql demo5.yslog -p 'read_verilog -formal demo5.v; prep -top demo5 -nordff; write_smt2 -wires demo5.smt2'
demo6.smt2: demo6.v
yosys -ql demo6.yslog -p 'read_verilog demo6.v; prep -top demo6 -nordff; assertpmux; opt -keepdc -fast; write_smt2 -wires demo6.smt2'
demo7.smt2: demo7.v
yosys -ql demo7.yslog -p 'read_verilog -formal demo7.v; prep -top demo7 -nordff; write_smt2 -wires demo7.smt2'
clean:
rm -f demo1.yslog demo1.smt2 demo1.vcd
rm -f demo2.yslog demo2.smt2 demo2.vcd demo2.smtc demo2_tb.v demo2_tb demo2_tb.vcd
rm -f demo3.yslog demo3.smt2 demo3.vcd
rm -f demo4.yslog demo4.smt2 demo4.vcd
rm -f demo5.yslog demo5.smt2 demo5.vcd
rm -f demo6.yslog demo6.smt2
rm -f demo7.yslog demo7.smt2
.PHONY: demo1 demo2 demo3 demo4 demo5 demo6 demo7 clean

View File

@ -0,0 +1,19 @@
module demo1(input clk, input addtwo, output iseven);
reg [3:0] cnt;
wire [3:0] next_cnt;
inc inc_inst (addtwo, iseven, cnt, next_cnt);
always @(posedge clk)
cnt = (iseven ? cnt == 10 : cnt == 11) ? 0 : next_cnt;
`ifdef FORMAL
assert property (cnt != 15);
initial assume (!cnt[2]);
`endif
endmodule
module inc(input addtwo, output iseven, input [3:0] a, output [3:0] y);
assign iseven = !a[0];
assign y = a + (addtwo ? 2 : 1);
endmodule

View File

@ -0,0 +1,29 @@
// Nothing to prove in this demo.
// Just an example for memories, vcd dumps and vlog testbench dumps.
`ifdef FORMAL
`define assume(_expr_) assume(_expr_)
`else
`define assume(_expr_)
`endif
module demo2(input clk, input [4:0] addr, output reg [31:0] data);
reg [31:0] mem [0:31];
always @(posedge clk)
data <= mem[addr];
reg [31:0] used_addr = 0;
reg [31:0] used_dbits = 0;
reg initstate = 1;
always @(posedge clk) begin
initstate <= 0;
`assume(!used_addr[addr]);
used_addr[addr] <= 1;
if (!initstate) begin
`assume(data != 0);
`assume((used_dbits & data) == 0);
used_dbits <= used_dbits | data;
end
end
endmodule

View File

@ -0,0 +1,5 @@
initial
assume [rst]
always -1
assert (= [-1:mem] [mem])

View File

@ -0,0 +1,18 @@
// Whatever the initial content of this memory is at reset, it will never change
// see demo3.smtc for assumptions and assertions
module demo3(input clk, rst, input [15:0] addr, output reg [31:0] data);
reg [31:0] mem [0:2**16-1];
reg [15:0] addr_q;
always @(posedge clk) begin
if (rst) begin
data <= mem[0] ^ 123456789;
addr_q <= 0;
end else begin
mem[addr_q] <= data ^ 123456789;
data <= mem[addr] ^ 123456789;
addr_q <= addr;
end
end
endmodule

View File

@ -0,0 +1,11 @@
initial
assume [rst]
always -1
assume (not [rst])
assume (=> [-1:inv2] [inv2])
final -2
assume [-1:inv2]
assume (not [-2:inv2])
assert (= [r1] [r2])

View File

@ -0,0 +1,13 @@
// Demo for "final" smtc constraints
module demo4(input clk, rst, inv2, input [15:0] in, output reg [15:0] r1, r2);
always @(posedge clk) begin
if (rst) begin
r1 <= in;
r2 <= -in;
end else begin
r1 <= r1 + in;
r2 <= inv2 ? -(r2 - in) : (r2 - in);
end
end
endmodule

View File

@ -0,0 +1,18 @@
// Demo for $anyconst
module demo5 (input clk);
wire [7:0] step_size = $anyconst;
reg [7:0] state = 0, count = 0;
reg [31:0] hash = 0;
always @(posedge clk) begin
count <= count + 1;
hash <= ((hash << 5) + hash) ^ state;
state <= state + step_size;
end
always @* begin
if (count == 42)
assert(hash == 32'h A18FAC0A);
end
endmodule

View File

@ -0,0 +1,14 @@
// Demo for assertpmux
module demo6 (input A, B, C, D, E, output reg Y);
always @* begin
Y = 0;
if (A != B) begin
(* parallel_case *)
case (C)
A: Y = D;
B: Y = E;
endcase
end
end
endmodule

View File

@ -0,0 +1,19 @@
// Demo for memory initialization
module demo7;
wire [2:0] addr = $anyseq;
reg [15:0] memory [0:7];
initial begin
memory[0] = 1331;
memory[1] = 1331 + 1;
memory[2] = 1331 + 2;
memory[3] = 1331 + 4;
memory[4] = 1331 + 8;
memory[5] = 1331 + 16;
memory[6] = 1331 + 32;
memory[7] = 1331 + 64;
end
assert property (1000 < memory[addr] && memory[addr] < 2000);
endmodule

View File

@ -0,0 +1,6 @@
OBJS += frontends/ast/ast.o
OBJS += frontends/ast/simplify.o
OBJS += frontends/ast/genrtlil.o
OBJS += frontends/ast/dpicall.o

1180
yosys/frontends/ast/ast.cc Normal file

File diff suppressed because it is too large Load Diff

319
yosys/frontends/ast/ast.h Normal file
View File

@ -0,0 +1,319 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ---
*
* This is the AST frontend library.
*
* The AST frontend library is not a frontend on it's own but provides a
* generic abstract syntax tree (AST) abstraction for HDL code and can be
* used by HDL frontends. See "ast.h" for an overview of the API and the
* Verilog frontend for an usage example.
*
*/
#ifndef AST_H
#define AST_H
#include "kernel/rtlil.h"
#include <stdint.h>
#include <set>
YOSYS_NAMESPACE_BEGIN
namespace AST
{
// all node types, type2str() must be extended
// whenever a new node type is added here
enum AstNodeType
{
AST_NONE,
AST_DESIGN,
AST_MODULE,
AST_TASK,
AST_FUNCTION,
AST_DPI_FUNCTION,
AST_WIRE,
AST_MEMORY,
AST_AUTOWIRE,
AST_PARAMETER,
AST_LOCALPARAM,
AST_DEFPARAM,
AST_PARASET,
AST_ARGUMENT,
AST_RANGE,
AST_MULTIRANGE,
AST_CONSTANT,
AST_REALVALUE,
AST_CELLTYPE,
AST_IDENTIFIER,
AST_PREFIX,
AST_ASSERT,
AST_ASSUME,
AST_FCALL,
AST_TO_BITS,
AST_TO_SIGNED,
AST_TO_UNSIGNED,
AST_CONCAT,
AST_REPLICATE,
AST_BIT_NOT,
AST_BIT_AND,
AST_BIT_OR,
AST_BIT_XOR,
AST_BIT_XNOR,
AST_REDUCE_AND,
AST_REDUCE_OR,
AST_REDUCE_XOR,
AST_REDUCE_XNOR,
AST_REDUCE_BOOL,
AST_SHIFT_LEFT,
AST_SHIFT_RIGHT,
AST_SHIFT_SLEFT,
AST_SHIFT_SRIGHT,
AST_LT,
AST_LE,
AST_EQ,
AST_NE,
AST_EQX,
AST_NEX,
AST_GE,
AST_GT,
AST_ADD,
AST_SUB,
AST_MUL,
AST_DIV,
AST_MOD,
AST_POW,
AST_POS,
AST_NEG,
AST_LOGIC_AND,
AST_LOGIC_OR,
AST_LOGIC_NOT,
AST_TERNARY,
AST_MEMRD,
AST_MEMWR,
AST_MEMINIT,
AST_TCALL,
AST_ASSIGN,
AST_CELL,
AST_PRIMITIVE,
AST_CELLARRAY,
AST_ALWAYS,
AST_INITIAL,
AST_BLOCK,
AST_ASSIGN_EQ,
AST_ASSIGN_LE,
AST_CASE,
AST_COND,
AST_CONDX,
AST_CONDZ,
AST_DEFAULT,
AST_FOR,
AST_WHILE,
AST_REPEAT,
AST_GENVAR,
AST_GENFOR,
AST_GENIF,
AST_GENCASE,
AST_GENBLOCK,
AST_POSEDGE,
AST_NEGEDGE,
AST_EDGE,
AST_PACKAGE
};
// convert an node type to a string (e.g. for debug output)
std::string type2str(AstNodeType type);
// The AST is built using instances of this struct
struct AstNode
{
// for dict<> and pool<>
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
// this nodes type
AstNodeType type;
// the list of child nodes for this node
std::vector<AstNode*> children;
// the list of attributes assigned to this node
std::map<RTLIL::IdString, AstNode*> attributes;
bool get_bool_attribute(RTLIL::IdString id);
// node content - most of it is unused in most node types
std::string str;
std::vector<RTLIL::State> bits;
bool is_input, is_output, is_reg, is_signed, is_string, range_valid, range_swapped;
int port_id, range_left, range_right;
uint32_t integer;
double realvalue;
// if this is a multirange memory then this vector contains offset and length of each dimension
std::vector<int> multirange_dimensions;
// this is set by simplify and used during RTLIL generation
AstNode *id2ast;
// this is used by simplify to detect if basic analysis has been performed already on the node
bool basic_prep;
// this is the original sourcecode location that resulted in this AST node
// it is automatically set by the constructor using AST::current_filename and
// the AST::get_line_num() callback function.
std::string filename;
int linenum;
// creating and deleting nodes
AstNode(AstNodeType type = AST_NONE, AstNode *child1 = NULL, AstNode *child2 = NULL, AstNode *child3 = NULL);
AstNode *clone();
void cloneInto(AstNode *other);
void delete_children();
~AstNode();
enum mem2reg_flags
{
/* status flags */
MEM2REG_FL_ALL = 0x00000001,
MEM2REG_FL_ASYNC = 0x00000002,
MEM2REG_FL_INIT = 0x00000004,
/* candidate flags */
MEM2REG_FL_FORCED = 0x00000100,
MEM2REG_FL_SET_INIT = 0x00000200,
MEM2REG_FL_SET_ELSE = 0x00000400,
MEM2REG_FL_SET_ASYNC = 0x00000800,
MEM2REG_FL_EQ2 = 0x00001000,
MEM2REG_FL_CMPLX_LHS = 0x00002000,
/* proc flags */
MEM2REG_FL_EQ1 = 0x01000000,
};
// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.
// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param);
AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);
void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map);
void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules);
void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block);
bool mem2reg_check(pool<AstNode*> &mem2reg_set);
void mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes);
void meminfo(int &mem_width, int &mem_size, int &addr_bits);
// additional functionality for evaluating constant functions
struct varinfo_t { RTLIL::Const val; int offset; bool is_signed; };
bool has_const_only_constructs(bool &recommend_const_eval);
void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
AstNode *eval_const_function(AstNode *fcall);
// create a human-readable text representation of the AST (for debugging)
void dumpAst(FILE *f, std::string indent);
void dumpVlog(FILE *f, std::string indent);
// used by genRTLIL() for detecting expression width and sign
void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL);
void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL);
// create RTLIL code for this AST node
// for expressions the resulting signal vector is returned
// all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module
RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false);
RTLIL::SigSpec genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
// compare AST nodes
bool operator==(const AstNode &other) const;
bool operator!=(const AstNode &other) const;
bool contains(const AstNode *other) const;
// helper functions for creating AST nodes for constants
static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32);
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed);
static AstNode *mkconst_str(const std::vector<RTLIL::State> &v);
static AstNode *mkconst_str(const std::string &str);
// helper function for creating sign-extended const objects
RTLIL::Const bitsAsConst(int width, bool is_signed);
RTLIL::Const bitsAsConst(int width = -1);
RTLIL::Const asAttrConst();
RTLIL::Const asParaConst();
uint64_t asInt(bool is_signed);
bool bits_only_01();
bool asBool();
// helper functions for real valued const eval
int isConst(); // return '1' for AST_CONSTANT and '2' for AST_REALVALUE
double asReal(bool is_signed);
RTLIL::Const realAsConst(int width);
};
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool dump_rtlil, bool nolatches, bool nomeminit,
bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
// parametric modules are supported directly by the AST library
// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
struct AstModule : RTLIL::Module {
AstNode *ast;
bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
virtual ~AstModule();
virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters);
virtual RTLIL::Module *clone() const;
};
// this must be set by the language frontend before parsing the sources
// the AstNode constructor then uses current_filename and get_line_num()
// to initialize the filename and linenum properties of new nodes
extern std::string current_filename;
extern void (*set_line_num)(int);
extern int (*get_line_num)();
// set set_line_num and get_line_num to internal dummy functions (done by simplify() and AstModule::derive
// to control the filename and linenum properties of new nodes not generated by a frontend parser)
void use_internal_line_num();
// call a DPI function
AstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args);
}
namespace AST_INTERNAL
{
// internal state variables
extern bool flag_dump_ast1, flag_dump_ast2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
extern bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
extern AST::AstNode *current_ast, *current_ast_mod;
extern std::map<std::string, AST::AstNode*> current_scope;
extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
extern RTLIL::SigSpec ignoreThisSignalsInInitial;
extern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child;
extern AST::AstModule *current_module;
extern bool current_always_clocked;
struct ProcessGenerator;
}
YOSYS_NAMESPACE_END
#endif

View File

@ -0,0 +1,148 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "ast.h"
#ifdef YOSYS_ENABLE_PLUGINS
#include <dlfcn.h>
#include <ffi.h>
YOSYS_NAMESPACE_BEGIN
typedef void (*ffi_fptr) ();
static ffi_fptr resolve_fn (std::string symbol_name)
{
if (symbol_name.find(':') != std::string::npos)
{
int pos = symbol_name.find(':');
std::string plugin_name = symbol_name.substr(0, pos);
std::string real_symbol_name = symbol_name.substr(pos+1);
while (loaded_plugin_aliases.count(plugin_name))
plugin_name = loaded_plugin_aliases.at(plugin_name);
if (loaded_plugins.count(plugin_name) == 0)
log_error("unable to resolve '%s': can't find plugin `%s'\n", symbol_name.c_str(), plugin_name.c_str());
void *symbol = dlsym(loaded_plugins.at(plugin_name), real_symbol_name.c_str());
if (symbol == nullptr)
log_error("unable to resolve '%s': can't find symbol `%s' in plugin `%s'\n",
symbol_name.c_str(), real_symbol_name.c_str(), plugin_name.c_str());
return (ffi_fptr) symbol;
}
for (auto &it : loaded_plugins) {
void *symbol = dlsym(it.second, symbol_name.c_str());
if (symbol != nullptr)
return (ffi_fptr) symbol;
}
void *symbol = dlsym(RTLD_DEFAULT, symbol_name.c_str());
if (symbol != nullptr)
return (ffi_fptr) symbol;
log_error("unable to resolve '%s'.\n", symbol_name.c_str());
}
AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args)
{
AST::AstNode *newNode = nullptr;
union { double f64; float f32; int32_t i32; } value_store [args.size() + 1];
ffi_type *types [args.size() + 1];
void *values [args.size() + 1];
ffi_cif cif;
int status;
log("Calling DPI function `%s' and returning `%s':\n", fname.c_str(), rtype.c_str());
log_assert(GetSize(args) == GetSize(argtypes));
for (int i = 0; i < GetSize(args); i++) {
if (argtypes[i] == "real") {
log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
value_store[i].f64 = args[i]->asReal(args[i]->is_signed);
values[i] = &value_store[i].f64;
types[i] = &ffi_type_double;
} else if (argtypes[i] == "shortreal") {
log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
value_store[i].f32 = args[i]->asReal(args[i]->is_signed);
values[i] = &value_store[i].f32;
types[i] = &ffi_type_double;
} else if (argtypes[i] == "integer") {
log(" arg %d (%s): %lld\n", i, argtypes[i].c_str(), (long long)args[i]->asInt(args[i]->is_signed));
value_store[i].i32 = args[i]->asInt(args[i]->is_signed);
values[i] = &value_store[i].i32;
types[i] = &ffi_type_sint32;
} else {
log_error("invalid argtype '%s' for argument %d.\n", argtypes[i].c_str(), i);
}
}
if (rtype == "integer") {
types[args.size()] = &ffi_type_slong;
values[args.size()] = &value_store[args.size()].i32;
} else if (rtype == "shortreal") {
types[args.size()] = &ffi_type_float;
values[args.size()] = &value_store[args.size()].f32;
} else if (rtype == "real") {
types[args.size()] = &ffi_type_double;
values[args.size()] = &value_store[args.size()].f64;
} else {
log_error("invalid rtype '%s'.\n", rtype.c_str());
}
if ((status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, args.size(), types[args.size()], types)) != FFI_OK)
log_error("ffi_prep_cif failed: status %d.\n", status);
ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values);
if (rtype == "real") {
newNode = new AstNode(AST_REALVALUE);
newNode->realvalue = value_store[args.size()].f64;
log(" return realvalue: %g\n", newNode->asReal(true));
} else if (rtype == "shortreal") {
newNode = new AstNode(AST_REALVALUE);
newNode->realvalue = value_store[args.size()].f32;
log(" return realvalue: %g\n", newNode->asReal(true));
} else {
newNode = AstNode::mkconst_int(value_store[args.size()].i32, false);
log(" return integer: %lld\n", (long long)newNode->asInt(true));
}
return newNode;
}
YOSYS_NAMESPACE_END
#else /* YOSYS_ENABLE_PLUGINS */
YOSYS_NAMESPACE_BEGIN
AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&)
{
log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str());
}
YOSYS_NAMESPACE_END
#endif /* YOSYS_ENABLE_PLUGINS */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
OBJS += frontends/blif/blifparse.o

View File

@ -0,0 +1,495 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "blifparse.h"
YOSYS_NAMESPACE_BEGIN
static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count, std::istream &f)
{
string strbuf;
int buffer_len = 0;
buffer[0] = 0;
while (1)
{
buffer_len += strlen(buffer + buffer_len);
while (buffer_len > 0 && (buffer[buffer_len-1] == ' ' || buffer[buffer_len-1] == '\t' ||
buffer[buffer_len-1] == '\r' || buffer[buffer_len-1] == '\n'))
buffer[--buffer_len] = 0;
if (buffer_size-buffer_len < 4096) {
buffer_size *= 2;
buffer = (char*)realloc(buffer, buffer_size);
}
if (buffer_len == 0 || buffer[buffer_len-1] == '\\') {
if (buffer_len > 0 && buffer[buffer_len-1] == '\\')
buffer[--buffer_len] = 0;
line_count++;
if (!std::getline(f, strbuf))
return false;
while (buffer_size-buffer_len < strbuf.size()+1) {
buffer_size *= 2;
buffer = (char*)realloc(buffer, buffer_size);
}
strcpy(buffer+buffer_len, strbuf.c_str());
} else
return true;
}
}
void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean, bool sop_mode)
{
RTLIL::Module *module = nullptr;
RTLIL::Const *lutptr = NULL;
RTLIL::Cell *sopcell = NULL;
RTLIL::State lut_default_state = RTLIL::State::Sx;
int blif_maxnum = 0, sopmode = -1;
auto blif_wire = [&](const std::string &wire_name) -> Wire*
{
if (wire_name[0] == '$')
{
for (int i = 0; i+1 < GetSize(wire_name); i++)
{
if (wire_name[i] != '$')
continue;
int len = 0;
while (i+len+1 < GetSize(wire_name) && '0' <= wire_name[i+len+1] && wire_name[i+len+1] <= '9')
len++;
if (len > 0) {
string num_str = wire_name.substr(i+1, len);
int num = atoi(num_str.c_str()) & 0x0fffffff;
blif_maxnum = std::max(blif_maxnum, num);
}
}
}
IdString wire_id = RTLIL::escape_id(wire_name);
Wire *wire = module->wire(wire_id);
if (wire == nullptr)
wire = module->addWire(wire_id);
return wire;
};
dict<RTLIL::IdString, RTLIL::Const> *obj_attributes = nullptr;
dict<RTLIL::IdString, RTLIL::Const> *obj_parameters = nullptr;
size_t buffer_size = 4096;
char *buffer = (char*)malloc(buffer_size);
int line_count = 0;
while (1)
{
if (!read_next_line(buffer, buffer_size, line_count, f)) {
if (module != nullptr)
goto error;
free(buffer);
return;
}
continue_without_read:
if (buffer[0] == '#')
continue;
if (buffer[0] == '.')
{
if (lutptr) {
for (auto &bit : lutptr->bits)
if (bit == RTLIL::State::Sx)
bit = lut_default_state;
lutptr = NULL;
lut_default_state = RTLIL::State::Sx;
}
if (sopcell) {
sopcell = NULL;
sopmode = -1;
}
char *cmd = strtok(buffer, " \t\r\n");
if (!strcmp(cmd, ".model")) {
if (module != nullptr)
goto error;
module = new RTLIL::Module;
module->name = RTLIL::escape_id(strtok(NULL, " \t\r\n"));
obj_attributes = &module->attributes;
obj_parameters = nullptr;
if (design->module(module->name))
log_error("Duplicate definition of module %s in line %d!\n", log_id(module->name), line_count);
design->add(module);
continue;
}
if (module == nullptr)
goto error;
if (!strcmp(cmd, ".end"))
{
module->fixup_ports();
if (run_clean)
{
Const buffer_lut(vector<RTLIL::State>({State::S0, State::S1}));
vector<Cell*> remove_cells;
for (auto cell : module->cells())
if (cell->type == "$lut" && cell->getParam("\\LUT") == buffer_lut) {
module->connect(cell->getPort("\\Y"), cell->getPort("\\A"));
remove_cells.push_back(cell);
}
for (auto cell : remove_cells)
module->remove(cell);
Wire *true_wire = module->wire("$true");
Wire *false_wire = module->wire("$false");
Wire *undef_wire = module->wire("$undef");
if (true_wire != nullptr)
module->rename(true_wire, stringf("$true$%d", ++blif_maxnum));
if (false_wire != nullptr)
module->rename(false_wire, stringf("$false$%d", ++blif_maxnum));
if (undef_wire != nullptr)
module->rename(undef_wire, stringf("$undef$%d", ++blif_maxnum));
autoidx = std::max(autoidx, blif_maxnum+1);
blif_maxnum = 0;
}
module = nullptr;
obj_attributes = nullptr;
obj_parameters = nullptr;
continue;
}
if (!strcmp(cmd, ".inputs") || !strcmp(cmd, ".outputs")) {
char *p;
while ((p = strtok(NULL, " \t\r\n")) != NULL) {
RTLIL::IdString wire_name(stringf("\\%s", p));
RTLIL::Wire *wire = module->wire(wire_name);
if (wire == nullptr)
wire = module->addWire(wire_name);
if (!strcmp(cmd, ".inputs"))
wire->port_input = true;
else
wire->port_output = true;
}
obj_attributes = nullptr;
obj_parameters = nullptr;
continue;
}
if (!strcmp(cmd, ".attr") || !strcmp(cmd, ".param")) {
char *n = strtok(NULL, " \t\r\n");
char *v = strtok(NULL, "\r\n");
IdString id_n = RTLIL::escape_id(n);
Const const_v;
if (v[0] == '"') {
std::string str(v+1);
if (str.back() == '"')
str.resize(str.size()-1);
const_v = Const(str);
} else {
int n = strlen(v);
const_v.bits.resize(n);
for (int i = 0; i < n; i++)
const_v.bits[i] = v[n-i-1] != '0' ? State::S1 : State::S0;
}
if (!strcmp(cmd, ".attr")) {
if (obj_attributes == nullptr)
goto error;
(*obj_attributes)[id_n] = const_v;
} else {
if (obj_parameters == nullptr)
goto error;
(*obj_parameters)[id_n] = const_v;
}
continue;
}
if (!strcmp(cmd, ".latch"))
{
char *d = strtok(NULL, " \t\r\n");
char *q = strtok(NULL, " \t\r\n");
char *edge = strtok(NULL, " \t\r\n");
char *clock = strtok(NULL, " \t\r\n");
char *init = strtok(NULL, " \t\r\n");
RTLIL::Cell *cell = nullptr;
if (clock == nullptr && edge != nullptr) {
init = edge;
edge = nullptr;
}
if (init != nullptr && (init[0] == '0' || init[0] == '1'))
blif_wire(q)->attributes["\\init"] = Const(init[0] == '1' ? 1 : 0, 1);
if (clock == nullptr)
goto no_latch_clock;
if (!strcmp(edge, "re"))
cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q));
else if (!strcmp(edge, "fe"))
cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false);
else if (!strcmp(edge, "ah"))
cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q));
else if (!strcmp(edge, "al"))
cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false);
else {
no_latch_clock:
if (dff_name.empty()) {
cell = module->addFf(NEW_ID, blif_wire(d), blif_wire(q));
} else {
cell = module->addCell(NEW_ID, dff_name);
cell->setPort("\\D", blif_wire(d));
cell->setPort("\\Q", blif_wire(q));
}
}
obj_attributes = &cell->attributes;
obj_parameters = &cell->parameters;
continue;
}
if (!strcmp(cmd, ".gate") || !strcmp(cmd, ".subckt"))
{
char *p = strtok(NULL, " \t\r\n");
if (p == NULL)
goto error;
IdString celltype = RTLIL::escape_id(p);
RTLIL::Cell *cell = module->addCell(NEW_ID, celltype);
while ((p = strtok(NULL, " \t\r\n")) != NULL) {
char *q = strchr(p, '=');
if (q == NULL || !q[0])
goto error;
*(q++) = 0;
cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec());
}
obj_attributes = &cell->attributes;
obj_parameters = &cell->parameters;
continue;
}
obj_attributes = nullptr;
obj_parameters = nullptr;
if (!strcmp(cmd, ".barbuf"))
{
char *p = strtok(NULL, " \t\r\n");
if (p == NULL)
goto error;
char *q = strtok(NULL, " \t\r\n");
if (q == NULL)
goto error;
module->connect(blif_wire(q), blif_wire(p));
continue;
}
if (!strcmp(cmd, ".names"))
{
char *p;
RTLIL::SigSpec input_sig, output_sig;
while ((p = strtok(NULL, " \t\r\n")) != NULL)
input_sig.append(blif_wire(p));
output_sig = input_sig.extract(input_sig.size()-1, 1);
input_sig = input_sig.extract(0, input_sig.size()-1);
if (input_sig.size() == 0)
{
RTLIL::State state = RTLIL::State::Sa;
while (1) {
if (!read_next_line(buffer, buffer_size, line_count, f))
goto error;
for (int i = 0; buffer[i]; i++) {
if (buffer[i] == ' ' || buffer[i] == '\t')
continue;
if (i == 0 && buffer[i] == '.')
goto finished_parsing_constval;
if (buffer[i] == '0') {
if (state == RTLIL::State::S1)
goto error;
state = RTLIL::State::S0;
continue;
}
if (buffer[i] == '1') {
if (state == RTLIL::State::S0)
goto error;
state = RTLIL::State::S1;
continue;
}
goto error;
}
}
finished_parsing_constval:
if (state == RTLIL::State::Sa)
state = RTLIL::State::S0;
if (output_sig.as_wire()->name == "$undef")
state = RTLIL::State::Sx;
module->connect(RTLIL::SigSig(output_sig, state));
goto continue_without_read;
}
if (sop_mode)
{
sopcell = module->addCell(NEW_ID, "$sop");
sopcell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size());
sopcell->parameters["\\DEPTH"] = 0;
sopcell->parameters["\\TABLE"] = RTLIL::Const();
sopcell->setPort("\\A", input_sig);
sopcell->setPort("\\Y", output_sig);
sopmode = -1;
}
else
{
RTLIL::Cell *cell = module->addCell(NEW_ID, "$lut");
cell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size());
cell->parameters["\\LUT"] = RTLIL::Const(RTLIL::State::Sx, 1 << input_sig.size());
cell->setPort("\\A", input_sig);
cell->setPort("\\Y", output_sig);
lutptr = &cell->parameters.at("\\LUT");
lut_default_state = RTLIL::State::Sx;
}
continue;
}
goto error;
}
if (lutptr == NULL && sopcell == NULL)
goto error;
char *input = strtok(buffer, " \t\r\n");
char *output = strtok(NULL, " \t\r\n");
if (input == NULL || output == NULL || (strcmp(output, "0") && strcmp(output, "1")))
goto error;
int input_len = strlen(input);
if (sopcell)
{
log_assert(sopcell->parameters["\\WIDTH"].as_int() == input_len);
sopcell->parameters["\\DEPTH"] = sopcell->parameters["\\DEPTH"].as_int() + 1;
for (int i = 0; i < input_len; i++)
switch (input[i]) {
case '0':
sopcell->parameters["\\TABLE"].bits.push_back(State::S1);
sopcell->parameters["\\TABLE"].bits.push_back(State::S0);
break;
case '1':
sopcell->parameters["\\TABLE"].bits.push_back(State::S0);
sopcell->parameters["\\TABLE"].bits.push_back(State::S1);
break;
default:
sopcell->parameters["\\TABLE"].bits.push_back(State::S0);
sopcell->parameters["\\TABLE"].bits.push_back(State::S0);
break;
}
if (sopmode == -1) {
sopmode = (*output == '1');
if (!sopmode) {
SigSpec outnet = sopcell->getPort("\\Y");
SigSpec tempnet = module->addWire(NEW_ID);
module->addNotGate(NEW_ID, tempnet, outnet);
sopcell->setPort("\\Y", tempnet);
}
} else
log_assert(sopmode == (*output == '1'));
}
if (lutptr)
{
if (input_len > 8)
goto error;
for (int i = 0; i < (1 << input_len); i++) {
for (int j = 0; j < input_len; j++) {
char c1 = input[j];
if (c1 != '-') {
char c2 = (i & (1 << j)) != 0 ? '1' : '0';
if (c1 != c2)
goto try_next_value;
}
}
lutptr->bits.at(i) = !strcmp(output, "0") ? RTLIL::State::S0 : RTLIL::State::S1;
try_next_value:;
}
lut_default_state = !strcmp(output, "0") ? RTLIL::State::S1 : RTLIL::State::S0;
}
}
error:
log_error("Syntax error in line %d!\n", line_count);
}
struct BlifFrontend : public Frontend {
BlifFrontend() : Frontend("blif", "read BLIF file") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" read_blif [filename]\n");
log("\n");
log("Load modules from a BLIF file into the current design.\n");
log("\n");
log(" -sop\n");
log(" Create $sop cells instead of $lut cells\n");
log("\n");
}
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
bool sop_mode = false;
log_header(design, "Executing BLIF frontend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if (arg == "-sop") {
sop_mode = true;
continue;
}
break;
}
extra_args(f, filename, args, argidx);
parse_blif(design, *f, "", true, sop_mode);
}
} BlifFrontend;
YOSYS_NAMESPACE_END

View File

@ -0,0 +1,31 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef ABC_BLIFPARSE
#define ABC_BLIFPARSE
#include "kernel/yosys.h"
YOSYS_NAMESPACE_BEGIN
extern void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean = false, bool sop_mode = false);
YOSYS_NAMESPACE_END
#endif

4
yosys/frontends/ilang/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
ilang_lexer.cc
ilang_parser.output
ilang_parser.tab.cc
ilang_parser.tab.h

View File

@ -0,0 +1,20 @@
GENFILES += frontends/ilang/ilang_parser.tab.cc
GENFILES += frontends/ilang/ilang_parser.tab.h
GENFILES += frontends/ilang/ilang_parser.output
GENFILES += frontends/ilang/ilang_lexer.cc
frontends/ilang/ilang_parser.tab.cc: frontends/ilang/ilang_parser.y
$(Q) mkdir -p $(dir $@)
$(P) $(BISON) -d -r all -b frontends/ilang/ilang_parser $<
$(Q) mv frontends/ilang/ilang_parser.tab.c frontends/ilang/ilang_parser.tab.cc
frontends/ilang/ilang_parser.tab.h: frontends/ilang/ilang_parser.tab.cc
frontends/ilang/ilang_lexer.cc: frontends/ilang/ilang_lexer.l
$(Q) mkdir -p $(dir $@)
$(P) flex -o frontends/ilang/ilang_lexer.cc $<
OBJS += frontends/ilang/ilang_parser.tab.o frontends/ilang/ilang_lexer.o
OBJS += frontends/ilang/ilang_frontend.o

View File

@ -0,0 +1,64 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ---
*
* A very simple and straightforward frontend for the RTLIL text
* representation (as generated by the 'ilang' backend).
*
*/
#include "ilang_frontend.h"
#include "kernel/register.h"
#include "kernel/log.h"
void rtlil_frontend_ilang_yyerror(char const *s)
{
YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_ilang_yyget_lineno(), s);
}
YOSYS_NAMESPACE_BEGIN
struct IlangFrontend : public Frontend {
IlangFrontend() : Frontend("ilang", "read modules from ilang file") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" read_ilang [filename]\n");
log("\n");
log("Load modules from an ilang file to the current design. (ilang is a text\n");
log("representation of a design in yosys's internal format.)\n");
log("\n");
}
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
log_header(design, "Executing ILANG frontend.\n");
extra_args(f, filename, args, 1);
log("Input filename: %s\n", filename.c_str());
ILANG_FRONTEND::lexin = f;
ILANG_FRONTEND::current_design = design;
rtlil_frontend_ilang_yydebug = false;
rtlil_frontend_ilang_yyrestart(NULL);
rtlil_frontend_ilang_yyparse();
rtlil_frontend_ilang_yylex_destroy();
}
} IlangFrontend;
YOSYS_NAMESPACE_END

View File

@ -0,0 +1,48 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ---
*
* A very simple and straightforward frontend for the RTLIL text
* representation (as generated by the 'ilang' backend).
*
*/
#ifndef ILANG_FRONTEND_H
#define ILANG_FRONTEND_H
#include "kernel/yosys.h"
YOSYS_NAMESPACE_BEGIN
namespace ILANG_FRONTEND {
extern std::istream *lexin;
extern RTLIL::Design *current_design;
}
YOSYS_NAMESPACE_END
extern int rtlil_frontend_ilang_yydebug;
int rtlil_frontend_ilang_yylex(void);
void rtlil_frontend_ilang_yyerror(char const *s);
void rtlil_frontend_ilang_yyrestart(FILE *f);
int rtlil_frontend_ilang_yyparse(void);
int rtlil_frontend_ilang_yylex_destroy(void);
int rtlil_frontend_ilang_yyget_lineno(void);
#endif

View File

@ -0,0 +1,138 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ---
*
* A very simple and straightforward frontend for the RTLIL text
* representation (as generated by the 'ilang' backend).
*
*/
%{
#ifdef __clang__
// bison generates code using the 'register' storage class specifier
#pragma clang diagnostic ignored "-Wdeprecated-register"
#endif
#include "frontends/ilang/ilang_frontend.h"
#include "ilang_parser.tab.h"
USING_YOSYS_NAMESPACE
#define YY_INPUT(buf,result,max_size) \
result = readsome(*ILANG_FRONTEND::lexin, buf, max_size)
%}
%option yylineno
%option noyywrap
%option nounput
%option prefix="rtlil_frontend_ilang_yy"
%x STRING
%%
"autoidx" { return TOK_AUTOIDX; }
"module" { return TOK_MODULE; }
"attribute" { return TOK_ATTRIBUTE; }
"parameter" { return TOK_PARAMETER; }
"signed" { return TOK_SIGNED; }
"wire" { return TOK_WIRE; }
"memory" { return TOK_MEMORY; }
"width" { return TOK_WIDTH; }
"upto" { return TOK_UPTO; }
"offset" { return TOK_OFFSET; }
"size" { return TOK_SIZE; }
"input" { return TOK_INPUT; }
"output" { return TOK_OUTPUT; }
"inout" { return TOK_INOUT; }
"cell" { return TOK_CELL; }
"connect" { return TOK_CONNECT; }
"switch" { return TOK_SWITCH; }
"case" { return TOK_CASE; }
"assign" { return TOK_ASSIGN; }
"sync" { return TOK_SYNC; }
"low" { return TOK_LOW; }
"high" { return TOK_HIGH; }
"posedge" { return TOK_POSEDGE; }
"negedge" { return TOK_NEGEDGE; }
"edge" { return TOK_EDGE; }
"always" { return TOK_ALWAYS; }
"global" { return TOK_GLOBAL; }
"init" { return TOK_INIT; }
"update" { return TOK_UPDATE; }
"process" { return TOK_PROCESS; }
"end" { return TOK_END; }
[a-z]+ { return TOK_INVALID; }
"\\"[^ \t\r\n]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; }
"$"[^ \t\r\n]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; }
"."[0-9]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; }
[0-9]+'[01xzm-]* { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_VALUE; }
-?[0-9]+ { rtlil_frontend_ilang_yylval.integer = atoi(yytext); return TOK_INT; }
\" { BEGIN(STRING); }
<STRING>\\. { yymore(); }
<STRING>\" {
BEGIN(0);
char *yystr = strdup(yytext);
yystr[strlen(yytext) - 1] = 0;
int i = 0, j = 0;
while (yystr[i]) {
if (yystr[i] == '\\' && yystr[i + 1]) {
i++;
if (yystr[i] == 'n')
yystr[i] = '\n';
else if (yystr[i] == 't')
yystr[i] = '\t';
else if ('0' <= yystr[i] && yystr[i] <= '7') {
yystr[i] = yystr[i] - '0';
if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') {
yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0';
i++;
}
if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') {
yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0';
i++;
}
}
}
yystr[j++] = yystr[i++];
}
yystr[j] = 0;
rtlil_frontend_ilang_yylval.string = yystr;
return TOK_STRING;
}
<STRING>. { yymore(); }
"#"[^\n]* /* ignore comments */
[ \t] /* ignore non-newline whitespaces */
[\r\n]+ { return TOK_EOL; }
. { return *yytext; }
%%
// this is a hack to avoid the 'yyinput defined but not used' error msgs
void *rtlil_frontend_ilang_avoid_input_warnings() {
return (void*)&yyinput;
}

View File

@ -0,0 +1,430 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ---
*
* A very simple and straightforward frontend for the RTLIL text
* representation (as generated by the 'ilang' backend).
*
*/
%{
#include <list>
#include "frontends/ilang/ilang_frontend.h"
YOSYS_NAMESPACE_BEGIN
namespace ILANG_FRONTEND {
std::istream *lexin;
RTLIL::Design *current_design;
RTLIL::Module *current_module;
RTLIL::Wire *current_wire;
RTLIL::Memory *current_memory;
RTLIL::Cell *current_cell;
RTLIL::Process *current_process;
std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
std::vector<RTLIL::CaseRule*> case_stack;
dict<RTLIL::IdString, RTLIL::Const> attrbuf;
}
using namespace ILANG_FRONTEND;
YOSYS_NAMESPACE_END
USING_YOSYS_NAMESPACE
%}
%name-prefix "rtlil_frontend_ilang_yy"
%union {
char *string;
int integer;
YOSYS_NAMESPACE_PREFIX RTLIL::Const *data;
YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec;
std::vector<YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec> *rsigspec;
}
%token <string> TOK_ID TOK_VALUE TOK_STRING
%token <integer> TOK_INT
%token TOK_AUTOIDX TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT
%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT
%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO
%type <rsigspec> sigspec_list_reversed
%type <sigspec> sigspec sigspec_list
%type <integer> sync_type
%type <data> constant
%expect 0
%debug
%%
input:
optional_eol {
attrbuf.clear();
} design {
if (attrbuf.size() != 0)
rtlil_frontend_ilang_yyerror("dangling attribute");
};
EOL:
optional_eol TOK_EOL;
optional_eol:
optional_eol TOK_EOL | /* empty */;
design:
design module |
design attr_stmt |
design autoidx_stmt |
/* empty */;
module:
TOK_MODULE TOK_ID EOL {
if (current_design->has($2))
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str());
current_module = new RTLIL::Module;
current_module->name = $2;
current_module->attributes = attrbuf;
current_design->add(current_module);
attrbuf.clear();
free($2);
} module_body TOK_END {
if (attrbuf.size() != 0)
rtlil_frontend_ilang_yyerror("dangling attribute");
current_module->fixup_ports();
} EOL;
module_body:
module_body module_stmt |
/* empty */;
module_stmt:
param_stmt | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt;
param_stmt:
TOK_PARAMETER TOK_ID EOL {
current_module->avail_parameters.insert($2);
free($2);
};
attr_stmt:
TOK_ATTRIBUTE TOK_ID constant EOL {
attrbuf[$2] = *$3;
delete $3;
free($2);
};
autoidx_stmt:
TOK_AUTOIDX TOK_INT EOL {
autoidx = max(autoidx, $2);
};
wire_stmt:
TOK_WIRE {
current_wire = current_module->addWire("$__ilang_frontend_tmp__");
current_wire->attributes = attrbuf;
attrbuf.clear();
} wire_options TOK_ID EOL {
if (current_module->wires_.count($4) != 0)
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of wire %s.", $4).c_str());
current_module->rename(current_wire, $4);
free($4);
};
wire_options:
wire_options TOK_WIDTH TOK_INT {
current_wire->width = $3;
} |
wire_options TOK_UPTO {
current_wire->upto = true;
} |
wire_options TOK_OFFSET TOK_INT {
current_wire->start_offset = $3;
} |
wire_options TOK_INPUT TOK_INT {
current_wire->port_id = $3;
current_wire->port_input = true;
current_wire->port_output = false;
} |
wire_options TOK_OUTPUT TOK_INT {
current_wire->port_id = $3;
current_wire->port_input = false;
current_wire->port_output = true;
} |
wire_options TOK_INOUT TOK_INT {
current_wire->port_id = $3;
current_wire->port_input = true;
current_wire->port_output = true;
} |
/* empty */;
memory_stmt:
TOK_MEMORY {
current_memory = new RTLIL::Memory;
current_memory->attributes = attrbuf;
attrbuf.clear();
} memory_options TOK_ID EOL {
if (current_module->memories.count($4) != 0)
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of memory %s.", $4).c_str());
current_memory->name = $4;
current_module->memories[$4] = current_memory;
free($4);
};
memory_options:
memory_options TOK_WIDTH TOK_INT {
current_memory->width = $3;
} |
memory_options TOK_SIZE TOK_INT {
current_memory->size = $3;
} |
memory_options TOK_OFFSET TOK_INT {
current_memory->start_offset = $3;
} |
/* empty */;
cell_stmt:
TOK_CELL TOK_ID TOK_ID EOL {
if (current_module->cells_.count($3) != 0)
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell %s.", $3).c_str());
current_cell = current_module->addCell($3, $2);
current_cell->attributes = attrbuf;
attrbuf.clear();
free($2);
free($3);
} cell_body TOK_END EOL;
cell_body:
cell_body TOK_PARAMETER TOK_ID constant EOL {
current_cell->parameters[$3] = *$4;
free($3);
delete $4;
} |
cell_body TOK_PARAMETER TOK_SIGNED TOK_ID constant EOL {
current_cell->parameters[$4] = *$5;
current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_SIGNED;
free($4);
delete $5;
} |
cell_body TOK_CONNECT TOK_ID sigspec EOL {
if (current_cell->hasPort($3))
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str());
current_cell->setPort($3, *$4);
delete $4;
free($3);
} |
/* empty */;
proc_stmt:
TOK_PROCESS TOK_ID EOL {
if (current_module->processes.count($2) != 0)
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of process %s.", $2).c_str());
current_process = new RTLIL::Process;
current_process->name = $2;
current_process->attributes = attrbuf;
current_module->processes[$2] = current_process;
switch_stack.clear();
switch_stack.push_back(&current_process->root_case.switches);
case_stack.clear();
case_stack.push_back(&current_process->root_case);
attrbuf.clear();
free($2);
} case_body sync_list TOK_END EOL;
switch_stmt:
attr_list TOK_SWITCH sigspec EOL {
RTLIL::SwitchRule *rule = new RTLIL::SwitchRule;
rule->signal = *$3;
rule->attributes = attrbuf;
switch_stack.back()->push_back(rule);
attrbuf.clear();
delete $3;
} switch_body TOK_END EOL;
attr_list:
/* empty */ |
attr_list attr_stmt;
switch_body:
switch_body TOK_CASE {
RTLIL::CaseRule *rule = new RTLIL::CaseRule;
switch_stack.back()->back()->cases.push_back(rule);
switch_stack.push_back(&rule->switches);
case_stack.push_back(rule);
} compare_list EOL case_body {
switch_stack.pop_back();
case_stack.pop_back();
} |
/* empty */;
compare_list:
sigspec {
case_stack.back()->compare.push_back(*$1);
delete $1;
} |
compare_list ',' sigspec {
case_stack.back()->compare.push_back(*$3);
delete $3;
} |
/* empty */;
case_body:
case_body switch_stmt |
case_body assign_stmt |
/* empty */;
assign_stmt:
TOK_ASSIGN sigspec sigspec EOL {
case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3));
delete $2;
delete $3;
};
sync_list:
sync_list TOK_SYNC sync_type sigspec EOL {
RTLIL::SyncRule *rule = new RTLIL::SyncRule;
rule->type = RTLIL::SyncType($3);
rule->signal = *$4;
current_process->syncs.push_back(rule);
delete $4;
} update_list |
sync_list TOK_SYNC TOK_ALWAYS EOL {
RTLIL::SyncRule *rule = new RTLIL::SyncRule;
rule->type = RTLIL::SyncType::STa;
rule->signal = RTLIL::SigSpec();
current_process->syncs.push_back(rule);
} update_list |
sync_list TOK_SYNC TOK_GLOBAL EOL {
RTLIL::SyncRule *rule = new RTLIL::SyncRule;
rule->type = RTLIL::SyncType::STg;
rule->signal = RTLIL::SigSpec();
current_process->syncs.push_back(rule);
} update_list |
sync_list TOK_SYNC TOK_INIT EOL {
RTLIL::SyncRule *rule = new RTLIL::SyncRule;
rule->type = RTLIL::SyncType::STi;
rule->signal = RTLIL::SigSpec();
current_process->syncs.push_back(rule);
} update_list |
/* empty */;
sync_type:
TOK_LOW { $$ = RTLIL::ST0; } |
TOK_HIGH { $$ = RTLIL::ST1; } |
TOK_POSEDGE { $$ = RTLIL::STp; } |
TOK_NEGEDGE { $$ = RTLIL::STn; } |
TOK_EDGE { $$ = RTLIL::STe; };
update_list:
update_list TOK_UPDATE sigspec sigspec EOL {
current_process->syncs.back()->actions.push_back(RTLIL::SigSig(*$3, *$4));
delete $3;
delete $4;
} |
/* empty */;
constant:
TOK_VALUE {
char *ep;
int width = strtol($1, &ep, 10);
std::list<RTLIL::State> bits;
while (*(++ep) != 0) {
RTLIL::State bit = RTLIL::Sx;
switch (*ep) {
case '0': bit = RTLIL::S0; break;
case '1': bit = RTLIL::S1; break;
case 'x': bit = RTLIL::Sx; break;
case 'z': bit = RTLIL::Sz; break;
case '-': bit = RTLIL::Sa; break;
case 'm': bit = RTLIL::Sm; break;
}
bits.push_front(bit);
}
if (bits.size() == 0)
bits.push_back(RTLIL::Sx);
while ((int)bits.size() < width) {
RTLIL::State bit = bits.back();
if (bit == RTLIL::S1)
bit = RTLIL::S0;
bits.push_back(bit);
}
while ((int)bits.size() > width)
bits.pop_back();
$$ = new RTLIL::Const;
for (auto it = bits.begin(); it != bits.end(); it++)
$$->bits.push_back(*it);
free($1);
} |
TOK_INT {
$$ = new RTLIL::Const($1, 32);
} |
TOK_STRING {
$$ = new RTLIL::Const($1);
free($1);
};
sigspec:
constant {
$$ = new RTLIL::SigSpec(*$1);
delete $1;
} |
TOK_ID {
if (current_module->wires_.count($1) == 0)
rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str());
$$ = new RTLIL::SigSpec(current_module->wires_[$1]);
free($1);
} |
TOK_ID '[' TOK_INT ']' {
if (current_module->wires_.count($1) == 0)
rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str());
$$ = new RTLIL::SigSpec(current_module->wires_[$1], $3);
free($1);
} |
TOK_ID '[' TOK_INT ':' TOK_INT ']' {
if (current_module->wires_.count($1) == 0)
rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str());
$$ = new RTLIL::SigSpec(current_module->wires_[$1], $5, $3 - $5 + 1);
free($1);
} |
'{' sigspec_list '}' {
$$ = $2;
};
sigspec_list_reversed:
sigspec_list_reversed sigspec {
$$->push_back(*$2);
delete $2;
} |
/* empty */ {
$$ = new std::vector<RTLIL::SigSpec>;
};
sigspec_list: sigspec_list_reversed {
$$ = new RTLIL::SigSpec;
for (auto it = $1->rbegin(); it != $1->rend(); it++)
$$->append(*it);
delete $1;
};
conn_stmt:
TOK_CONNECT sigspec sigspec EOL {
if (attrbuf.size() != 0)
rtlil_frontend_ilang_yyerror("dangling attribute");
current_module->connect(*$2, *$3);
delete $2;
delete $3;
};

View File

@ -0,0 +1,3 @@
OBJS += frontends/liberty/liberty.o

View File

@ -0,0 +1,660 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "passes/techmap/libparse.h"
#include "kernel/register.h"
#include "kernel/log.h"
YOSYS_NAMESPACE_BEGIN
struct token_t {
char type;
RTLIL::SigSpec sig;
token_t (char t) : type(t) { }
token_t (char t, RTLIL::SigSpec s) : type(t), sig(s) { }
};
static RTLIL::SigSpec parse_func_identifier(RTLIL::Module *module, const char *&expr)
{
log_assert(*expr != 0);
int id_len = 0;
while (('a' <= expr[id_len] && expr[id_len] <= 'z') || ('A' <= expr[id_len] && expr[id_len] <= 'Z') ||
('0' <= expr[id_len] && expr[id_len] <= '9') || expr[id_len] == '.' || expr[id_len] == '_') id_len++;
if (id_len == 0)
log_error("Expected identifier at `%s'.\n", expr);
if (id_len == 1 && (*expr == '0' || *expr == '1'))
return *(expr++) == '0' ? RTLIL::State::S0 : RTLIL::State::S1;
std::string id = RTLIL::escape_id(std::string(expr, id_len));
if (!module->wires_.count(id))
log_error("Can't resolve wire name %s.\n", RTLIL::unescape_id(id).c_str());
expr += id_len;
return module->wires_.at(id);
}
static RTLIL::SigSpec create_inv_cell(RTLIL::Module *module, RTLIL::SigSpec A)
{
RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_");
cell->setPort("\\A", A);
cell->setPort("\\Y", module->addWire(NEW_ID));
return cell->getPort("\\Y");
}
static RTLIL::SigSpec create_xor_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B)
{
RTLIL::Cell *cell = module->addCell(NEW_ID, "$_XOR_");
cell->setPort("\\A", A);
cell->setPort("\\B", B);
cell->setPort("\\Y", module->addWire(NEW_ID));
return cell->getPort("\\Y");
}
static RTLIL::SigSpec create_and_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B)
{
RTLIL::Cell *cell = module->addCell(NEW_ID, "$_AND_");
cell->setPort("\\A", A);
cell->setPort("\\B", B);
cell->setPort("\\Y", module->addWire(NEW_ID));
return cell->getPort("\\Y");
}
static RTLIL::SigSpec create_or_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B)
{
RTLIL::Cell *cell = module->addCell(NEW_ID, "$_OR_");
cell->setPort("\\A", A);
cell->setPort("\\B", B);
cell->setPort("\\Y", module->addWire(NEW_ID));
return cell->getPort("\\Y");
}
static bool parse_func_reduce(RTLIL::Module *module, std::vector<token_t> &stack, token_t next_token)
{
int top = int(stack.size())-1;
if (0 <= top-1 && stack[top].type == 0 && stack[top-1].type == '!') {
token_t t = token_t(0, create_inv_cell(module, stack[top].sig));
stack.pop_back();
stack.pop_back();
stack.push_back(t);
return true;
}
if (0 <= top-1 && stack[top].type == '\'' && stack[top-1].type == 0) {
token_t t = token_t(0, create_inv_cell(module, stack[top-1].sig));
stack.pop_back();
stack.pop_back();
stack.push_back(t);
return true;
}
if (0 <= top && stack[top].type == 0) {
if (next_token.type == '\'')
return false;
stack[top].type = 1;
return true;
}
if (0 <= top-2 && stack[top-2].type == 1 && stack[top-1].type == '^' && stack[top].type == 1) {
token_t t = token_t(1, create_xor_cell(module, stack[top-2].sig, stack[top].sig));
stack.pop_back();
stack.pop_back();
stack.pop_back();
stack.push_back(t);
return true;
}
if (0 <= top && stack[top].type == 1) {
if (next_token.type == '^')
return false;
stack[top].type = 2;
return true;
}
if (0 <= top-1 && stack[top-1].type == 2 && stack[top].type == 2) {
token_t t = token_t(2, create_and_cell(module, stack[top-1].sig, stack[top].sig));
stack.pop_back();
stack.pop_back();
stack.push_back(t);
return true;
}
if (0 <= top-2 && stack[top-2].type == 2 && (stack[top-1].type == '*' || stack[top-1].type == '&') && stack[top].type == 2) {
token_t t = token_t(2, create_and_cell(module, stack[top-2].sig, stack[top].sig));
stack.pop_back();
stack.pop_back();
stack.pop_back();
stack.push_back(t);
return true;
}
if (0 <= top && stack[top].type == 2) {
if (next_token.type == '*' || next_token.type == '&' || next_token.type == 0 || next_token.type == '(')
return false;
stack[top].type = 3;
return true;
}
if (0 <= top-2 && stack[top-2].type == 3 && (stack[top-1].type == '+' || stack[top-1].type == '|') && stack[top].type == 3) {
token_t t = token_t(3, create_or_cell(module, stack[top-2].sig, stack[top].sig));
stack.pop_back();
stack.pop_back();
stack.pop_back();
stack.push_back(t);
return true;
}
if (0 <= top-2 && stack[top-2].type == '(' && stack[top-1].type == 3 && stack[top].type == ')') {
token_t t = token_t(0, stack[top-1].sig);
stack.pop_back();
stack.pop_back();
stack.pop_back();
stack.push_back(t);
return true;
}
return false;
}
static RTLIL::SigSpec parse_func_expr(RTLIL::Module *module, const char *expr)
{
const char *orig_expr = expr;
std::vector<token_t> stack;
while (*expr)
{
if (*expr == ' ' || *expr == '\t' || *expr == '\r' || *expr == '\n' || *expr == '"') {
expr++;
continue;
}
token_t next_token(0);
if (*expr == '(' || *expr == ')' || *expr == '\'' || *expr == '!' || *expr == '^' || *expr == '*' || *expr == '+' || *expr == '|')
next_token = token_t(*(expr++));
else
next_token = token_t(0, parse_func_identifier(module, expr));
while (parse_func_reduce(module, stack, next_token)) {}
stack.push_back(next_token);
}
while (parse_func_reduce(module, stack, token_t('.'))) {}
#if 0
for (size_t i = 0; i < stack.size(); i++)
if (stack[i].type < 16)
log("%3d: %d %s\n", int(i), stack[i].type, log_signal(stack[i].sig));
else
log("%3d: %c\n", int(i), stack[i].type);
#endif
if (stack.size() != 1 || stack.back().type != 3)
log_error("Parser error in function expr `%s'.\n", orig_expr);
return stack.back().sig;
}
static void create_ff(RTLIL::Module *module, LibertyAst *node)
{
RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0))));
RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1))));
RTLIL::SigSpec clk_sig, data_sig, clear_sig, preset_sig;
bool clk_polarity = true, clear_polarity = true, preset_polarity = true;
for (auto child : node->children) {
if (child->id == "clocked_on")
clk_sig = parse_func_expr(module, child->value.c_str());
if (child->id == "next_state")
data_sig = parse_func_expr(module, child->value.c_str());
if (child->id == "clear")
clear_sig = parse_func_expr(module, child->value.c_str());
if (child->id == "preset")
preset_sig = parse_func_expr(module, child->value.c_str());
}
if (clk_sig.size() == 0 || data_sig.size() == 0)
log_error("FF cell %s has no next_state and/or clocked_on attribute.\n", log_id(module->name));
for (bool rerun_invert_rollback = true; rerun_invert_rollback;)
{
rerun_invert_rollback = false;
for (auto &it : module->cells_) {
if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clk_sig) {
clk_sig = it.second->getPort("\\A");
clk_polarity = !clk_polarity;
rerun_invert_rollback = true;
}
if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clear_sig) {
clear_sig = it.second->getPort("\\A");
clear_polarity = !clear_polarity;
rerun_invert_rollback = true;
}
if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == preset_sig) {
preset_sig = it.second->getPort("\\A");
preset_polarity = !preset_polarity;
rerun_invert_rollback = true;
}
}
}
RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_");
cell->setPort("\\A", iq_sig);
cell->setPort("\\Y", iqn_sig);
cell = module->addCell(NEW_ID, "");
cell->setPort("\\D", data_sig);
cell->setPort("\\Q", iq_sig);
cell->setPort("\\C", clk_sig);
if (clear_sig.size() == 0 && preset_sig.size() == 0) {
cell->type = stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N');
}
if (clear_sig.size() == 1 && preset_sig.size() == 0) {
cell->type = stringf("$_DFF_%c%c0_", clk_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N');
cell->setPort("\\R", clear_sig);
}
if (clear_sig.size() == 0 && preset_sig.size() == 1) {
cell->type = stringf("$_DFF_%c%c1_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N');
cell->setPort("\\R", preset_sig);
}
if (clear_sig.size() == 1 && preset_sig.size() == 1) {
cell->type = stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N');
cell->setPort("\\S", preset_sig);
cell->setPort("\\R", clear_sig);
}
log_assert(!cell->type.empty());
}
static void create_latch(RTLIL::Module *module, LibertyAst *node)
{
RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0))));
RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1))));
RTLIL::SigSpec enable_sig, data_sig, clear_sig, preset_sig;
bool enable_polarity = true, clear_polarity = true, preset_polarity = true;
for (auto child : node->children) {
if (child->id == "enable")
enable_sig = parse_func_expr(module, child->value.c_str());
if (child->id == "data_in")
data_sig = parse_func_expr(module, child->value.c_str());
if (child->id == "clear")
clear_sig = parse_func_expr(module, child->value.c_str());
if (child->id == "preset")
preset_sig = parse_func_expr(module, child->value.c_str());
}
if (enable_sig.size() == 0 || data_sig.size() == 0)
log_error("Latch cell %s has no data_in and/or enable attribute.\n", log_id(module->name));
for (bool rerun_invert_rollback = true; rerun_invert_rollback;)
{
rerun_invert_rollback = false;
for (auto &it : module->cells_) {
if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == enable_sig) {
enable_sig = it.second->getPort("\\A");
enable_polarity = !enable_polarity;
rerun_invert_rollback = true;
}
if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clear_sig) {
clear_sig = it.second->getPort("\\A");
clear_polarity = !clear_polarity;
rerun_invert_rollback = true;
}
if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == preset_sig) {
preset_sig = it.second->getPort("\\A");
preset_polarity = !preset_polarity;
rerun_invert_rollback = true;
}
}
}
RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_");
cell->setPort("\\A", iq_sig);
cell->setPort("\\Y", iqn_sig);
if (clear_sig.size() == 1)
{
RTLIL::SigSpec clear_negative = clear_sig;
RTLIL::SigSpec clear_enable = clear_sig;
if (clear_polarity == true || clear_polarity != enable_polarity)
{
RTLIL::Cell *inv = module->addCell(NEW_ID, "$_NOT_");
inv->setPort("\\A", clear_sig);
inv->setPort("\\Y", module->addWire(NEW_ID));
if (clear_polarity == true)
clear_negative = inv->getPort("\\Y");
if (clear_polarity != enable_polarity)
clear_enable = inv->getPort("\\Y");
}
RTLIL::Cell *data_gate = module->addCell(NEW_ID, "$_AND_");
data_gate->setPort("\\A", data_sig);
data_gate->setPort("\\B", clear_negative);
data_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
RTLIL::Cell *enable_gate = module->addCell(NEW_ID, enable_polarity ? "$_OR_" : "$_AND_");
enable_gate->setPort("\\A", enable_sig);
enable_gate->setPort("\\B", clear_enable);
enable_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
}
if (preset_sig.size() == 1)
{
RTLIL::SigSpec preset_positive = preset_sig;
RTLIL::SigSpec preset_enable = preset_sig;
if (preset_polarity == false || preset_polarity != enable_polarity)
{
RTLIL::Cell *inv = module->addCell(NEW_ID, "$_NOT_");
inv->setPort("\\A", preset_sig);
inv->setPort("\\Y", module->addWire(NEW_ID));
if (preset_polarity == false)
preset_positive = inv->getPort("\\Y");
if (preset_polarity != enable_polarity)
preset_enable = inv->getPort("\\Y");
}
RTLIL::Cell *data_gate = module->addCell(NEW_ID, "$_OR_");
data_gate->setPort("\\A", data_sig);
data_gate->setPort("\\B", preset_positive);
data_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
RTLIL::Cell *enable_gate = module->addCell(NEW_ID, enable_polarity ? "$_OR_" : "$_AND_");
enable_gate->setPort("\\A", enable_sig);
enable_gate->setPort("\\B", preset_enable);
enable_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
}
cell = module->addCell(NEW_ID, stringf("$_DLATCH_%c_", enable_polarity ? 'P' : 'N'));
cell->setPort("\\D", data_sig);
cell->setPort("\\Q", iq_sig);
cell->setPort("\\E", enable_sig);
}
void parse_type_map(std::map<std::string, std::tuple<int, int, bool>> &type_map, LibertyAst *ast)
{
for (auto type_node : ast->children)
{
if (type_node->id != "type" || type_node->args.size() != 1)
continue;
std::string type_name = type_node->args.at(0);
int bit_width = -1, bit_from = -1, bit_to = -1;
bool upto = false;
for (auto child : type_node->children)
{
if (child->id == "base_type" && child->value != "array")
goto next_type;
if (child->id == "data_type" && child->value != "bit")
goto next_type;
if (child->id == "bit_width")
bit_width = atoi(child->value.c_str());
if (child->id == "bit_from")
bit_from = atoi(child->value.c_str());
if (child->id == "bit_to")
bit_to = atoi(child->value.c_str());
if (child->id == "downto" && (child->value == "0" || child->value == "false" || child->value == "FALSE"))
upto = true;
}
if (bit_width != (std::max(bit_from, bit_to) - std::min(bit_from, bit_to) + 1))
log_error("Incompatible array type '%s': bit_width=%d, bit_from=%d, bit_to=%d.\n",
type_name.c_str(), bit_width, bit_from, bit_to);
type_map[type_name] = std::tuple<int, int, bool>(bit_width, std::min(bit_from, bit_to), upto);
next_type:;
}
}
struct LibertyFrontend : public Frontend {
LibertyFrontend() : Frontend("liberty", "read cells from liberty file") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" read_liberty [filename]\n");
log("\n");
log("Read cells from liberty file as modules into current design.\n");
log("\n");
log(" -lib\n");
log(" only create empty blackbox modules\n");
log("\n");
log(" -ignore_redef\n");
log(" ignore re-definitions of modules. (the default behavior is to\n");
log(" create an error message.)\n");
log("\n");
log(" -ignore_miss_func\n");
log(" ignore cells with missing function specification of outputs\n");
log("\n");
log(" -ignore_miss_dir\n");
log(" ignore cells with a missing or invalid direction\n");
log(" specification on a pin\n");
log("\n");
log(" -setattr <attribute_name>\n");
log(" set the specified attribute (to the value 1) on all loaded modules\n");
log("\n");
}
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
bool flag_lib = false;
bool flag_ignore_redef = false;
bool flag_ignore_miss_func = false;
bool flag_ignore_miss_dir = false;
std::vector<std::string> attributes;
log_header(design, "Executing Liberty frontend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if (arg == "-lib") {
flag_lib = true;
continue;
}
if (arg == "-ignore_redef") {
flag_ignore_redef = true;
continue;
}
if (arg == "-ignore_miss_func") {
flag_ignore_miss_func = true;
continue;
}
if (arg == "-ignore_miss_dir") {
flag_ignore_miss_dir = true;
continue;
}
if (arg == "-setattr" && argidx+1 < args.size()) {
attributes.push_back(RTLIL::escape_id(args[++argidx]));
continue;
}
break;
}
extra_args(f, filename, args, argidx);
LibertyParser parser(*f);
int cell_count = 0;
std::map<std::string, std::tuple<int, int, bool>> global_type_map;
parse_type_map(global_type_map, parser.ast);
for (auto cell : parser.ast->children)
{
if (cell->id != "cell" || cell->args.size() != 1)
continue;
std::string cell_name = RTLIL::escape_id(cell->args.at(0));
if (design->has(cell_name)) {
if (flag_ignore_redef)
continue;
log_error("Duplicate definition of cell/module %s.\n", RTLIL::unescape_id(cell_name).c_str());
}
// log("Processing cell type %s.\n", RTLIL::unescape_id(cell_name).c_str());
std::map<std::string, std::tuple<int, int, bool>> type_map = global_type_map;
parse_type_map(type_map, cell);
RTLIL::Module *module = new RTLIL::Module;
module->name = cell_name;
if (flag_lib)
module->set_bool_attribute("\\blackbox");
for (auto &attr : attributes)
module->attributes[attr] = 1;
for (auto node : cell->children)
{
if (node->id == "pin" && node->args.size() == 1) {
LibertyAst *dir = node->find("direction");
if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal"))
{
if (!flag_ignore_miss_dir)
{
log_error("Missing or invalid direction for pin %s on cell %s.\n", node->args.at(0).c_str(), log_id(module->name));
} else {
log("Ignoring cell %s with missing or invalid direction for pin %s.\n", log_id(module->name), node->args.at(0).c_str());
delete module;
goto skip_cell;
}
}
if (!flag_lib || dir->value != "internal")
module->addWire(RTLIL::escape_id(node->args.at(0)));
}
if (node->id == "bus" && node->args.size() == 1)
{
if (!flag_lib)
log_error("Error in cell %s: bus interfaces are only supported in -lib mode.\n", log_id(cell_name));
LibertyAst *dir = node->find("direction");
if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal"))
log_error("Missing or invalid direction for bus %s on cell %s.\n", node->args.at(0).c_str(), log_id(module->name));
if (dir->value == "internal")
continue;
LibertyAst *bus_type_node = node->find("bus_type");
if (!bus_type_node || !type_map.count(bus_type_node->value))
log_error("Unkown or unsupported type for bus interface %s on cell %s.\n",
node->args.at(0).c_str(), log_id(cell_name));
int bus_type_width = std::get<0>(type_map.at(bus_type_node->value));
int bus_type_offset = std::get<1>(type_map.at(bus_type_node->value));
bool bus_type_upto = std::get<2>(type_map.at(bus_type_node->value));
Wire *wire = module->addWire(RTLIL::escape_id(node->args.at(0)), bus_type_width);
wire->start_offset = bus_type_offset;
wire->upto = bus_type_upto;
if (dir->value == "input" || dir->value == "inout")
wire->port_input = true;
if (dir->value == "output" || dir->value == "inout")
wire->port_output = true;
}
}
for (auto node : cell->children)
{
if (!flag_lib) {
if (node->id == "ff" && node->args.size() == 2)
create_ff(module, node);
if (node->id == "latch" && node->args.size() == 2)
create_latch(module, node);
}
if (node->id == "pin" && node->args.size() == 1)
{
LibertyAst *dir = node->find("direction");
if (flag_lib && dir->value == "internal")
continue;
RTLIL::Wire *wire = module->wires_.at(RTLIL::escape_id(node->args.at(0)));
if (dir && dir->value == "inout") {
wire->port_input = true;
wire->port_output = true;
}
if (dir && dir->value == "input") {
wire->port_input = true;
continue;
}
if (dir && dir->value == "output")
wire->port_output = true;
if (flag_lib)
continue;
LibertyAst *func = node->find("function");
if (func == NULL)
{
if (!flag_ignore_miss_func)
{
log_error("Missing function on output %s of cell %s.\n", log_id(wire->name), log_id(module->name));
} else {
log("Ignoring cell %s with missing function on output %s.\n", log_id(module->name), log_id(wire->name));
delete module;
goto skip_cell;
}
}
RTLIL::SigSpec out_sig = parse_func_expr(module, func->value.c_str());
module->connect(RTLIL::SigSig(wire, out_sig));
}
}
module->fixup_ports();
design->add(module);
cell_count++;
skip_cell:;
}
log("Imported %d cell types from liberty file.\n", cell_count);
}
} LibertyFrontend;
YOSYS_NAMESPACE_END

View File

@ -0,0 +1,17 @@
OBJS += frontends/verific/verific.o
ifeq ($(ENABLE_VERIFIC),1)
EXTRA_TARGETS += share/verific
share/verific:
$(P) rm -rf share/verific.new
$(Q) mkdir -p share/verific.new
$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1987/. share/verific.new/vhdl_vdbs_1987
$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1993/. share/verific.new/vhdl_vdbs_1993
$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2008/. share/verific.new/vhdl_vdbs_2008
$(Q) mv share/verific.new share/verific
endif

View File

@ -0,0 +1,30 @@
Notes on building yosys with verific support on amd64 when you
only have the i386 eval version of Verific:
1.) Use a Makefile.conf like the following one:
--snip--
CONFIG := clang
ENABLE_TCL := 0
ENABLE_PLUGINS := 0
ENABLE_VERIFIC := 1
CXXFLAGS += -m32
LDFLAGS += -m32
VERIFIC_DIR = /usr/local/src/verific_lib_eval
--snap--
2.) Install the necessary multilib packages
Hint: On debian/ubuntu the multilib packages have names such as
libreadline-dev:i386 or lib32readline6-dev, depending on the
exact version of debian/ubuntu you are working with.
3.) Build and test
make -j8
./yosys frontends/verific/test_navre.ys

View File

@ -0,0 +1,18 @@
verific -vlog2k ../yosys-bigsim/softusb_navre/rtl/softusb_navre.v
verific -import softusb_navre
memory softusb_navre
flatten softusb_navre
rename softusb_navre gate
read_verilog ../yosys-bigsim/softusb_navre/rtl/softusb_navre.v
cd softusb_navre; proc; opt; memory; opt; cd ..
rename softusb_navre gold
expose -dff -shared gold gate
miter -equiv -ignore_gold_x -make_assert -make_outputs -make_outcmp gold gate miter
cd miter
flatten; opt -undriven
sat -verify -maxsteps 5 -set-init-undef -set-def-inputs -prove-asserts -tempinduct-def \
-seq 1 -set-at 1 in_rst 1 # -show-inputs -show-outputs

File diff suppressed because it is too large Load Diff

4
yosys/frontends/verilog/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
verilog_lexer.cc
verilog_parser.output
verilog_parser.tab.cc
verilog_parser.tab.h

View File

@ -0,0 +1,23 @@
GENFILES += frontends/verilog/verilog_parser.tab.cc
GENFILES += frontends/verilog/verilog_parser.tab.h
GENFILES += frontends/verilog/verilog_parser.output
GENFILES += frontends/verilog/verilog_lexer.cc
frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y
$(Q) mkdir -p $(dir $@)
$(P) $(BISON) -d -r all -b frontends/verilog/verilog_parser $<
$(Q) mv frontends/verilog/verilog_parser.tab.c frontends/verilog/verilog_parser.tab.cc
frontends/verilog/verilog_parser.tab.h: frontends/verilog/verilog_parser.tab.cc
frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
$(Q) mkdir -p $(dir $@)
$(P) flex -o frontends/verilog/verilog_lexer.cc $<
OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o
OBJS += frontends/verilog/preproc.o
OBJS += frontends/verilog/verilog_frontend.o
OBJS += frontends/verilog/const2ast.o

View File

@ -0,0 +1,241 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ---
*
* The Verilog frontend.
*
* This frontend is using the AST frontend library (see frontends/ast/).
* Thus this frontend does not generate RTLIL code directly but creates an
* AST directly from the Verilog parse tree and then passes this AST to
* the AST frontend library.
*
* ---
*
* This file contains an ad-hoc parser for Verilog constants. The Verilog
* lexer does only recognize a constant but does not actually split it to its
* components. I.e. it just passes the Verilog code for the constant to the
* bison parser. The parser then uses the function const2ast() from this file
* to create an AST node for the constant.
*
*/
#include "verilog_frontend.h"
#include "kernel/log.h"
#include <string.h>
#include <math.h>
YOSYS_NAMESPACE_BEGIN
using namespace AST;
// divide an arbitrary length decimal number by two and return the rest
static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
{
int carry = 0;
for (size_t i = 0; i < digits.size(); i++) {
if (digits[i] >= 10)
log_error("Invalid use of [a-fxz?] in decimal constant at %s:%d.\n",
current_filename.c_str(), get_line_num());
digits[i] += carry * 10;
carry = digits[i] % 2;
digits[i] /= 2;
}
while (!digits.empty() && !digits.front())
digits.erase(digits.begin());
return carry;
}
// find the number of significant bits in a binary number (not including the sign bit)
static int my_ilog2(int x)
{
int ret = 0;
while (x != 0 && x != -1) {
x = x >> 1;
ret++;
}
return ret;
}
// parse a binary, decimal, hexadecimal or octal number with support for special bits ('x', 'z' and '?')
static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type)
{
// all digits in string (MSB at index 0)
std::vector<uint8_t> digits;
while (*str) {
if ('0' <= *str && *str <= '9')
digits.push_back(*str - '0');
else if ('a' <= *str && *str <= 'f')
digits.push_back(10 + *str - 'a');
else if ('A' <= *str && *str <= 'F')
digits.push_back(10 + *str - 'A');
else if (*str == 'x' || *str == 'X')
digits.push_back(0xf0);
else if (*str == 'z' || *str == 'Z')
digits.push_back(0xf1);
else if (*str == '?')
digits.push_back(0xf2);
str++;
}
if (base == 10 && GetSize(digits) == 1 && digits.front() >= 0xf0)
base = 2;
data.clear();
if (base == 10) {
while (!digits.empty())
data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0);
} else {
int bits_per_digit = my_ilog2(base-1);
for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) {
if (*it > (base-1) && *it < 0xf0)
log_error("Digit larger than %d used in in base-%d constant at %s:%d.\n",
base-1, base, current_filename.c_str(), get_line_num());
for (int i = 0; i < bits_per_digit; i++) {
int bitmask = 1 << i;
if (*it == 0xf0)
data.push_back(case_type == 'x' ? RTLIL::Sa : RTLIL::Sx);
else if (*it == 0xf1)
data.push_back(case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz);
else if (*it == 0xf2)
data.push_back(RTLIL::Sa);
else
data.push_back((*it & bitmask) ? RTLIL::S1 : RTLIL::S0);
}
}
}
int len = GetSize(data);
RTLIL::State msb = data.empty() ? RTLIL::S0 : data.back();
if (len_in_bits < 0) {
if (len < 32)
data.resize(32, msb == RTLIL::S0 || msb == RTLIL::S1 ? RTLIL::S0 : msb);
return;
}
for (len = len - 1; len >= 0; len--)
if (data[len] == RTLIL::S1)
break;
if (msb == RTLIL::S0 || msb == RTLIL::S1) {
len += 1;
data.resize(len_in_bits, RTLIL::S0);
} else {
len += 2;
data.resize(len_in_bits, msb);
}
if (len > len_in_bits)
log_warning("Literal has a width of %d bit, but value requires %d bit. (%s:%d)\n",
len_in_bits, len, current_filename.c_str(), get_line_num());
}
// convert the Verilog code for a constant to an AST node
AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn_z)
{
if (warn_z) {
AstNode *ret = const2ast(code, case_type);
if (std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n",
current_filename.c_str(), get_line_num());
return ret;
}
const char *str = code.c_str();
// Strings
if (*str == '"') {
int len = strlen(str) - 2;
std::vector<RTLIL::State> data;
data.reserve(len * 8);
for (int i = 0; i < len; i++) {
unsigned char ch = str[len - i];
for (int j = 0; j < 8; j++) {
data.push_back((ch & 1) ? RTLIL::S1 : RTLIL::S0);
ch = ch >> 1;
}
}
AstNode *ast = AstNode::mkconst_bits(data, false);
ast->str = code;
return ast;
}
for (size_t i = 0; i < code.size(); i++)
if (code[i] == '_' || code[i] == ' ' || code[i] == '\t' || code[i] == '\r' || code[i] == '\n')
code.erase(code.begin()+(i--));
str = code.c_str();
char *endptr;
long len_in_bits = strtol(str, &endptr, 10);
// Simple base-10 integer
if (*endptr == 0) {
std::vector<RTLIL::State> data;
my_strtobin(data, str, -1, 10, case_type);
if (data.back() == RTLIL::S1)
data.push_back(RTLIL::S0);
return AstNode::mkconst_bits(data, true);
}
// unsized constant
if (str == endptr)
len_in_bits = -1;
// The "<bits>'s?[bodhBODH]<digits>" syntax
if (*endptr == '\'')
{
std::vector<RTLIL::State> data;
bool is_signed = false;
if (*(endptr+1) == 's') {
is_signed = true;
endptr++;
}
switch (*(endptr+1))
{
case 'b':
case 'B':
my_strtobin(data, endptr+2, len_in_bits, 2, case_type);
break;
case 'o':
case 'O':
my_strtobin(data, endptr+2, len_in_bits, 8, case_type);
break;
case 'd':
case 'D':
my_strtobin(data, endptr+2, len_in_bits, 10, case_type);
break;
case 'h':
case 'H':
my_strtobin(data, endptr+2, len_in_bits, 16, case_type);
break;
default:
return NULL;
}
if (len_in_bits < 0) {
if (is_signed && data.back() == RTLIL::S1)
data.push_back(RTLIL::S0);
}
return AstNode::mkconst_bits(data, is_signed);
}
return NULL;
}
YOSYS_NAMESPACE_END

Some files were not shown because too many files have changed in this diff Show More