1
0
forked from tanchou/Verilog
This commit is contained in:
Gamenight77
2025-05-02 15:51:18 +02:00
parent 0faab53c30
commit f5e73d7379
105 changed files with 707398 additions and 1 deletions

4
Help/counter2/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
runs
.vscode
workspace.code-workspace
*.pyc

22
Help/counter2/README.md Normal file
View File

@@ -0,0 +1,22 @@
# Aim of the project
This project gives an example of the desired structure for a *Verilog* project. It is composed of the following folders:
- build : Contains (tcl) scripts to build a Vivado or other project out of this arborescence.
- constraints : Contains the constraints (if needed) for the project.
- ip : Contains external dependencies of the project. This folder is used for commodity only in order to simplify test and verification scripts. Its contents should be populated by a build script (or manually copied in some cases). Each subdirectory corresponds to a dependency in the same format as the current document. For old projects, at least *src* directory should be present. Normally, it should not be under version control.
- runs : Contains all temporary files built by the runs of different tools (e.g. simulation, verification etc.). It might have a substructure, depending on the tool. It **should not** be under version control.
- scripts : Contains different scripts related to the project. Typical examples - launch simulation or verification. The scripts might be in shell, makefile, tcl etc. A preference for tcl should be considered.
- src : Contains source files for the project. It has subdirectories corresponding to the HDL language used (Verilog, VHDL, Migen, Amaranth, etc)
- tests : Contains testbenches for the project. It has subdirectories corresponding to the used tool (cocotb, verilog, verilator, etc). For *python*-based tools, the corresponding structure should allow test discovery using pytest (file names containing *test* and functions containing *test*).
- verification : Contains scripts and files for formal verification.
- other folders that are related to the editor and that probably should not be under version control.
The project should be under version control (e.g. *git*) and have corresponding *.gitignore* specifications.
The root of the project shall only contain:
- a README.md file that gives the description of the project.
- *.gitignore* or similar files, related to the version control.
- a *Makefile* or a launcher script named *project* that have arguments allowing to run different tools. If present, it must contain at least the argument *clean* that will delete all elements from the *run* folder (maybe also all non-vcs tracked files).
- Editor-related files, e.g. *workspace.code-workspace* for VSCode. These files should not be under version control.

View File

@@ -0,0 +1 @@
@tclsh scripts\project.tcl %*

View File

@@ -0,0 +1,20 @@
puts "Starting TCL script"
#set path test1b_tb
#gtkwave::forceOpenTreeNode $path
set nfacs [ gtkwave::getNumFacs ]
puts "There are $nfacs signals"
set l [list]
for {set i 0} {$i < $nfacs } {incr i} {
set facname [ gtkwave::getFacName $i ]
set numdots [ expr {[llength [split $facname .]] - 1}]
# puts "$numdots"
if {$numdots == 1} {
lappend l "$facname"
puts "Added signal $facname"
}
}
set num_added [ gtkwave::addSignalsFromList $l ]
gtkwave::setZoomRangeTimes [ gtkwave::getMinTime ] [ gtkwave::getMaxTime ]
puts "Start time [ gtkwave::getMinTime ] end time: [ gtkwave::getMaxTime ]"

View File

@@ -0,0 +1,152 @@
# Tcl launcher script for the project
namespace eval project_launcher {
# Help information for this script
proc print_help {} {
variable script_file "project.tcl"
puts "\nDescription:"
puts "Perform actions related to this project.\n"
puts "Syntax:"
puts "$script_file"
puts "$script_file \[action\] \[args\]"
puts "Usage:"
puts "Name Description"
puts "-------------------------------------------------------------------------"
puts "\[action\] Determine the action to be performed. Default value: help\n"
puts " Current actions: help, clean, sim, verify, test\n"
puts "\[args\] Arguments related to the action.\n"
puts " --root <dir> changes the root reference for the project.\n"
puts "-------------------------------------------------------------------------\n"
exit 0
}
proc do_clean { root_dir } {
variable dir "$root_dir/runs"
puts "Cleaning all files in directory $dir...\n"
# Checking if the folder is empty to avoid error
if {[catch { glob "$dir/*" } result] != 1} {
file delete -force -- {*}[glob "$dir/*" ]
}
}
proc do_sim_icarus { root_dir verbose } {
# Checking if the folder is empty to avoid error
if {[file exists "$root_dir/scripts/run_iverilog.tcl"] == 1} {
#global root_dir_loc $root_dir
#source $root_dir/scripts/run_iverilog.tcl
try {
set results [exec tclsh $root_dir/scripts/run_iverilog.tcl $root_dir ]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
if {$status != 0} {
puts "Problem running the script :"
puts $results
return
}
if {[expr $verbose]} {
# output the result of the execution
puts $results
}
} else {
puts "The script run_iverilog.tcl does not exist in $root_dir/scripts"
}
}
proc do_sim_pytest { root_dir verbose } {
exec pytest $root_dir/tests/ >@stdout 2>@stderr
}
proc do_formal { root_dir } {
# We suppose that the sby file is meant to be run from the inside of the folder
# hence we cd there
if {[file pathtype $root_dir] != "absolute"} {
set root_dir "../$root_dir"
}
#set root_dir [file normalize $root_dir]
cd verification
#variable fname [glob -nocomplain $root_dir/verification/*.sby]
variable fname [glob -nocomplain *.sby]
if {[llength $fname]} {
set fname [lindex $fname 0]
puts "Using $fname file..."
exec sby -f $fname --prefix $root_dir/runs/verification/counter >@stdout 2>@stderr
} else {
puts "There are no .sby files present..."
cd ..
return
}
cd ..
}
proc main {} {
variable root_dir
# Set the reference directory to where the script is
#set root_dir [file dirname [info script]]
# Set the reference directory for source file relative paths (by default the value is script directory path)
set root_dir "."
# Use origin directory path location variable, if specified in the tcl shell
if { [info exists ::root_dir_loc] } {
set root_dir $::root_dir_loc
}
variable action "help"
variable verbose false
if { $::argc > 0 } {
for {set i 0} {$i < $::argc} {incr i} {
set option [string trim [lindex $::argv $i]]
switch -regexp -- $option {
"--root" { incr i; set root_dir [lindex $::argv $i] }
"--help" { print_help }
"help" { print_help }
"clean" { set action "clean" }
"sim" {incr i; set action "sim_[lindex $::argv $i]" }
"--verbose" { set verbose true }
"-v" { set verbose true }
{pytest|cocotb|test} {set action "pytest"}
{formal|verify|verification} {set action "formal"}
default {
if { [regexp {^-} $option] } {
puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n"
return 1
}
}
}
}
} else {
print_help
}
puts "Script started. The root dir is $root_dir. The action is: $action\n"
switch -regexp -- $action {
"clean" { do_clean $root_dir }
{sim_icarus|^sim_$|sim_iverilog} { do_sim_icarus $root_dir $verbose}
{sim_cocotb|pytest} { do_sim_pytest $root_dir $verbose}
"formal" { do_formal $root_dir}
}
}
main
}

View File

@@ -0,0 +1,133 @@
# Tcl script for iverilog simulation
namespace eval sim_iverilog {
# Help information for this script
proc print_help {} {
variable script_file "run_iverilog.tcl"
puts "\nDescription:"
puts "Runs the iverilog simulation.\n"
puts "Syntax:"
puts "$script_file"
puts "$script_file \[action\] \[args\]"
puts "Usage:"
puts "Name Description"
puts "-------------------------------------------------------------------------"
puts "\[action\] Determine the action to be performed. Default value: help\n"
puts " Current actions: help, clean\n"
puts "\[args\] Arguments related to the action.\n"
puts " --root <dir> changes the root reference for the project.\n"
puts "-------------------------------------------------------------------------\n"
exit 0
}
proc main {} {
variable root_dir
# Set the reference directory to where the script is
#set root_dir [file dirname [info script]]
# Set the reference directory for source file relative paths (by default the value is script directory path)
set root_dir "."
if { [info exists ::root_dir_loc] } {
set root_dir $::root_dir_loc
}
if { $::argc > 0 } {
set root_dir [lindex $::argv 0]
}
puts "Starting simulation using iverilog. The root dir is: $root_dir"
# variable root [file dirname [file normalize [info script]]]
# variable root [file dirname [file dirname [info script]]]
variable root $root_dir
variable source_path $root/src/verilog
variable sources {counter.v}
variable tb_path $root/tests/verilog
variable test_benches {counter_tb.v}
proc append_path {root list} {
set l {}
foreach f $list {
lappend l $root/$f
}
return $l
}
variable sources_full_path [append_path $source_path $sources]
variable tb_full_path [append_path $tb_path $test_benches]
variable output_dir $root/runs/sim/iverilog
variable additional_options "-D VCD_DUMP"
proc run_sim {tb} {
set name [file rootname $tb]
puts "Running test bench $name"
puts "Cleaning files..."
# file delete [glob -nocomplain $sim_iverilog::output_dir/*]
puts "Recreating path..."
file mkdir $sim_iverilog::output_dir
set iverilog_args "$sim_iverilog::additional_options -g2012 -Wall -I $sim_iverilog::source_path -Y .sv -y $sim_iverilog::source_path -o $sim_iverilog::output_dir/$name.vvp $sim_iverilog::tb_path/$tb $sim_iverilog::sources_full_path"
try {
set results [exec iverilog {*}$iverilog_args]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
if {$status != 0} {
puts "Problem running iverilog :"
puts $results
return
}
# output iverilog result
puts $results
set cwd [pwd]
puts "Running vvp..."
set vvp_cmd "vvp $name.vvp -lxt2"
cd $sim_iverilog::output_dir
#puts [pwd]
set results [exec {*}$vvp_cmd]
# output vvp result
puts $results
cd $cwd
puts "All done..."
}
foreach tb $test_benches {
run_sim $tb
}
exit 0
}
# run main
main
}

View File

@@ -0,0 +1,71 @@
`timescale 1ns/1ps
`default_nettype none
// Simple counter_reg with synchronous reset (and no load)
//
module counter #(
parameter WIDTH = 8,
parameter INITIAL_VALUE = 8'h0f
) (
input wire clk, // global clock
input wire reset, // synchronous reset signal
input wire en, // enable signal
output reg strobe // output strobe
);
initial strobe = 0;
reg[WIDTH-1:0] counter_reg = INITIAL_VALUE;
always @(posedge clk) begin
if (reset) begin
counter_reg <= INITIAL_VALUE;
end
else if (en) begin
strobe <= 0;
if (counter_reg == 0)
counter_reg <= INITIAL_VALUE;
else begin
if (counter_reg == 1)
strobe <= 1;
counter_reg <= counter_reg - 1;
end
end
end
`ifdef FORMAL
reg f_past_valid = 0;
always @* f_past_valid = !$initstate;
always @* begin
assume (counter_reg <= INITIAL_VALUE);
end
always @(posedge clk) begin
// if ($initstate) begin
// assume(counter_reg==INITIAL_VALUE);
// end
// if (!$initstate && $past(en)==1 && !$past(reset)) begin
if (f_past_valid && $past(en)==1 && !$past(reset)) begin
if (counter_reg < INITIAL_VALUE)
assert (counter_reg == $past(counter_reg) - 1);
else begin
assert(counter_reg == INITIAL_VALUE && $past(counter_reg)==0);
end
end
end
`endif
`ifdef VERIFIC
//internal_check: assert property (@(posedge clk)(counter_reg==11)|=>(counter_reg==10));
//assert property (@(posedge clk)(counter_reg==11 && en && !reset)|=>(counter_reg==10));
`endif
endmodule

View File

@@ -0,0 +1,27 @@
[tasks]
bmc
prove
cover
[options]
bmc: mode bmc
prove: mode prove
cover: mode cover
bmc: depth 100
[engines]
smtbmc
#smtbmc z3
#abc bmc3
[script]
read -verific
read -sv counter.v
read -formal counter_formal.sv
prep -top counter
[files]
../src/verilog/counter.v
counter_formal.sv

View File

@@ -0,0 +1,48 @@
`default_nettype none
module counter_formal (
input wire clk, // global clock
input wire reset, // synchronous reset signal
(*anyseq*) input wire en, // enable signal
input wire strobe, // output strobe
input wire [counter.WIDTH-1:0] counter_reg
);
`ifdef VERIFIC
internal_check: assert property (@(posedge clk)
disable iff (reset)
en && (counter_reg==11)|=>(counter_reg==10)) ;
decrease_enable_check: assert property (@(posedge clk)
disable iff (reset || !en)
(counter_reg >0 ) |=> (counter_reg == $past(counter_reg) - 1));
roll_enable_check: assert property (@(posedge clk)
disable iff (reset || !en)
(counter_reg == 0 ) |=> (counter_reg == counter.INITIAL_VALUE));
max_value_assert_check: assert property (
@(posedge clk)
(counter_reg <= counter.INITIAL_VALUE)
);
cover_0: cover property(
@(posedge clk)
(counter_reg == 0)
);
cover_2stb: cover property(
@(posedge clk)
(strobe == 1) |-> ##[+] (strobe == 1)
);
`endif
endmodule
bind counter counter_formal counter_f_inst(.*);
//testing: assert property (@(posedge clk)(counter_reg==111)|=>(counter_reg==10));

View File

@@ -0,0 +1,4 @@
runs
.vscode
workspace.code-workspace
*.pyc

View File

@@ -0,0 +1,4 @@
IO_LOC "led" 15;
IO_PORT "led" PULL_MODE=UP DRIVE=8 BANK_VCCIO=1.8;
IO_LOC "clk" 4;
IO_PORT "clk" PULL_MODE=UP BANK_VCCIO=1.8;

View File

@@ -0,0 +1,2 @@
@call c:\tools\oss-cad-suite\environment.bat
@tclsh scripts\project.tcl %*

View File

@@ -0,0 +1,20 @@
puts "Starting TCL script"
#set path test1b_tb
#gtkwave::forceOpenTreeNode $path
set nfacs [ gtkwave::getNumFacs ]
puts "There are $nfacs signals"
set l [list]
for {set i 0} {$i < $nfacs } {incr i} {
set facname [ gtkwave::getFacName $i ]
set numdots [ expr {[llength [split $facname .]] - 1}]
# puts "$numdots"
if {$numdots == 1} {
lappend l "$facname"
puts "Added signal $facname"
}
}
set num_added [ gtkwave::addSignalsFromList $l ]
gtkwave::setZoomRangeTimes [ gtkwave::getMinTime ] [ gtkwave::getMaxTime ]
puts "Start time [ gtkwave::getMinTime ] end time: [ gtkwave::getMaxTime ]"

View File

@@ -0,0 +1,184 @@
# Tcl launcher script for the project
namespace eval project_launcher {
# Help information for this script
proc print_help {} {
variable script_file "project.tcl"
puts "\nDescription:"
puts "Perform actions related to this project.\n"
puts "Syntax:"
puts "$script_file"
puts "$script_file \[action\] \[args\]"
puts "Usage:"
puts "Name Description"
puts "-------------------------------------------------------------------------"
puts "\[action\] Determine the action to be performed. Default value: help\n"
puts " Current actions: help, clean, sim, verify, test, view, elaborate\n"
puts "\[args\] Arguments related to the action.\n"
puts " --root <dir> changes the root reference for the project.\n"
puts "-------------------------------------------------------------------------\n"
exit 0
}
proc do_clean { root_dir } {
variable dir "$root_dir/runs"
puts "Cleaning all files in directory $dir...\n"
# Checking if the folder is empty to avoid error
if {[catch { glob "$dir/*" } result] != 1} {
file delete -force -- {*}[glob "$dir/*" ]
}
}
proc do_sim_icarus { root_dir verbose } {
# Checking if the folder is empty to avoid error
if {[file exists "$root_dir/scripts/run_iverilog.tcl"] == 1} {
#global root_dir_loc $root_dir
#source $root_dir/scripts/run_iverilog.tcl
try {
set results [exec tclsh $root_dir/scripts/run_iverilog.tcl $root_dir ]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
if {$status != 0} {
puts "Problem running the script :"
puts $results
return
}
if {[expr $verbose]} {
# output the result of the execution
puts $results
}
} else {
puts "The script run_iverilog.tcl does not exist in $root_dir/scripts"
}
}
proc do_sim_pytest { root_dir verbose } {
exec pytest $root_dir/tests/ >@stdout 2>@stderr
}
proc do_elaborate { root_dir } {
exec $root_dir/scripts/run_elaborate.bat
}
proc do_formal { root_dir } {
# We suppose that the sby file is meant to be run from the inside of the folder
# hence we cd there
if {[file pathtype $root_dir] != "absolute"} {
set root_dir "../$root_dir"
}
#set root_dir [file normalize $root_dir]
cd verification
#variable fname [glob -nocomplain $root_dir/verification/*.sby]
variable fname [glob -nocomplain *.sby]
if {[llength $fname]} {
set fname [lindex $fname 0]
puts "Using $fname file..."
exec sby -f $fname --prefix $root_dir/runs/verification/counter >@stdout 2>@stderr
} else {
puts "There are no .sby files present..."
cd ..
return
}
cd ..
}
proc do_view { root_dir } {
# Checking if the folder is empty to avoid error
if {[file exists "$root_dir/scripts/run_gtkwave.tcl"] == 1} {
try {
set results [exec tclsh $root_dir/scripts/run_gtkwave.tcl $root_dir ]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
if {$status != 0} {
puts "Problem running the script :"
puts $results
return
}
} else {
puts "The script run_gtkwave.tcl does not exist in $root_dir/scripts"
}
}
proc main {} {
variable root_dir
# Set the reference directory to where the script is
#set root_dir [file dirname [info script]]
# Set the reference directory for source file relative paths (by default the value is script directory path)
set root_dir "."
# Use origin directory path location variable, if specified in the tcl shell
if { [info exists ::root_dir_loc] } {
set root_dir $::root_dir_loc
}
variable action "help"
variable verbose false
if { $::argc > 0 } {
for {set i 0} {$i < $::argc} {incr i} {
set option [string trim [lindex $::argv $i]]
switch -regexp -- $option {
"--root" { incr i; set root_dir [lindex $::argv $i] }
"--help" { print_help }
"help" { print_help }
"clean" { set action "clean" }
"sim" {incr i; set action "sim_[lindex $::argv $i]" }
"--verbose" { set verbose true }
"-v" { set verbose true }
{pytest|cocotb|test} {set action "pytest"}
{formal|verify|verification} {set action "formal"}
{view} {set action "view"}
{elaborate} {set action "elaborate"}
default {
if { [regexp {^-} $option] } {
puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n"
return 1
}
}
}
}
} else {
print_help
}
puts "Script started. The root dir is $root_dir. The action is: $action\n"
switch -regexp -- $action {
"clean" { do_clean $root_dir }
{sim_icarus|^sim_$|sim_iverilog} { do_sim_icarus $root_dir $verbose}
{sim_cocotb|pytest} { do_sim_pytest $root_dir $verbose}
"formal" { do_formal $root_dir}
"view" {do_view $root_dir}
"elaborate" {do_elaborate $root_dir}
}
}
main
}

View File

@@ -0,0 +1,16 @@
@echo off
rem https://github.com/YosysHQ/apicula
set file_name=src\verilog\counter.v src\verilog\blink.v src\verilog\blink_top.v
set constraints_file=constraints\blink_led.cst
yosys -p "read_verilog -sv %file_name%; synth_gowin -json runs\blink_led_c.json"
set DEVICE=GW2AR-LV18QN88C8/I7
set BOARD=tangnano20k
nextpnr-himbaechel --json runs\blink_led_c.json --write runs\pnr_blink_led.json --device %DEVICE% --vopt cst=%constraints_file% --vopt family=GW2A-18C
gowin_pack -d %DEVICE% -o runs\blink_led_c.fs runs\pnr_blink_led.json
rem openfpgaloader -b %BOARD% blink_led_c.fs

View File

@@ -0,0 +1,88 @@
# Tcl script for iverilog simulation
namespace eval gtkwave {
# Help information for this script
proc print_help {} {
variable script_file "run_gtkwave.tcl"
puts "\nDescription:"
puts "Runs the iverilog simulation.\n"
puts "Syntax:"
puts "$script_file"
puts "$script_file \[action\] \[args\]"
puts "Usage:"
puts "Name Description"
puts "-------------------------------------------------------------------------"
puts "\[action\] Determine the action to be performed. Default value: help\n"
puts " Current actions: help, clean\n"
puts "\[args\] Arguments related to the action.\n"
puts " --root <dir> changes the root reference for the project.\n"
puts "-------------------------------------------------------------------------\n"
exit 0
}
proc main {} {
variable root_dir
# Set the reference directory to where the script is
#set root_dir [file dirname [info script]]
# Set the reference directory for source file relative paths (by default the value is script directory path)
set root_dir "."
if { [info exists ::root_dir_loc] } {
set root_dir $::root_dir_loc
}
if { $::argc > 0 } {
set root_dir [lindex $::argv 0]
}
puts "Starting gtkwave. The root dir is: $root_dir"
# variable root [file dirname [file normalize [info script]]]
# variable root [file dirname [file dirname [info script]]]
variable root $root_dir
variable view_file $root/runs/sim/iverilog/blink_tb.vcd
variable gtkwave_script $root/scripts/gtk_wave_all_signals.tcl
proc run_view {res} {
set name [file rootname $res]
# set iverilog_args "$sim_iverilog::additional_options -g2012 -Wall -I $sim_iverilog::source_path -Y .sv -y $sim_iverilog::source_path -o $sim_iverilog::output_dir/$name.vvp $sim_iverilog::tb_path/$tb $sim_iverilog::sources_full_path"
#set gtkwave_args "-S $gtkwave::gtkwave_script $gtkwave::view_file"
set gtkwave_args "$gtkwave::view_file"
#puts $gtkwave_args
try {
set results [exec gtkwave {*}$gtkwave_args]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
if {$status != 0} {
puts "Problem running gtkwave :"
puts $results
return
}
# output iverilog result
puts $results
}
run_view $root_dir
exit 0
}
# run main
main
}

View File

@@ -0,0 +1,133 @@
# Tcl script for iverilog simulation
namespace eval sim_iverilog {
# Help information for this script
proc print_help {} {
variable script_file "run_iverilog.tcl"
puts "\nDescription:"
puts "Runs the iverilog simulation.\n"
puts "Syntax:"
puts "$script_file"
puts "$script_file \[action\] \[args\]"
puts "Usage:"
puts "Name Description"
puts "-------------------------------------------------------------------------"
puts "\[action\] Determine the action to be performed. Default value: help\n"
puts " Current actions: help, clean\n"
puts "\[args\] Arguments related to the action.\n"
puts " --root <dir> changes the root reference for the project.\n"
puts "-------------------------------------------------------------------------\n"
exit 0
}
proc main {} {
variable root_dir
# Set the reference directory to where the script is
#set root_dir [file dirname [info script]]
# Set the reference directory for source file relative paths (by default the value is script directory path)
set root_dir "."
if { [info exists ::root_dir_loc] } {
set root_dir $::root_dir_loc
}
if { $::argc > 0 } {
set root_dir [lindex $::argv 0]
}
puts "Starting simulation using iverilog. The root dir is: $root_dir"
# variable root [file dirname [file normalize [info script]]]
# variable root [file dirname [file dirname [info script]]]
variable root $root_dir
variable source_path $root/src/verilog
variable sources {blink.v}
variable tb_path $root/tests/verilog
variable test_benches {blink_tb.v}
proc append_path {root list} {
set l {}
foreach f $list {
lappend l $root/$f
}
return $l
}
variable sources_full_path [append_path $source_path $sources]
variable tb_full_path [append_path $tb_path $test_benches]
variable output_dir $root/runs/sim/iverilog
variable additional_options "-D VCD_DUMP"
proc run_sim {tb} {
set name [file rootname $tb]
puts "Running test bench $name"
puts "Cleaning files..."
# file delete [glob -nocomplain $sim_iverilog::output_dir/*]
puts "Recreating path..."
file mkdir $sim_iverilog::output_dir
set iverilog_args "$sim_iverilog::additional_options -g2012 -Wall -I $sim_iverilog::source_path -Y .sv -y $sim_iverilog::source_path -o $sim_iverilog::output_dir/$name.vvp $sim_iverilog::tb_path/$tb $sim_iverilog::sources_full_path"
try {
set results [exec iverilog {*}$iverilog_args]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
if {$status != 0} {
puts "Problem running iverilog :"
puts $results
return
}
# output iverilog result
puts $results
set cwd [pwd]
puts "Running vvp..."
set vvp_cmd "vvp $name.vvp -lxt2"
cd $sim_iverilog::output_dir
#puts [pwd]
set results [exec {*}$vvp_cmd]
# output vvp result
puts $results
cd $cwd
puts "All done..."
}
foreach tb $test_benches {
run_sim $tb
}
exit 0
}
# run main
main
}

View File

@@ -0,0 +1,34 @@
`timescale 1ns/1ps
`default_nettype none
module blink #(
parameter CLK_SPEED = 27_000_000
)
(
input wire clk,
output reg led
);
wire strobe;
localparam ONE_HALF_S = CLK_SPEED / 2;
localparam ONE_S = CLK_SPEED ;
localparam TWO_S = CLK_SPEED *2;
localparam TIME = TWO_S;
localparam TIME_WIDTH = $clog2(TIME);
initial led = 0;
counter #(.WIDTH(TIME_WIDTH), .INITIAL_VALUE(TIME)) counter_inst
(
.clk(clk),
.reset(1'b0),
.en(1'b1),
.strobe(strobe)
);
always_ff @(posedge clk)
if(strobe) led <= !led;
endmodule

View File

@@ -0,0 +1,14 @@
module blink_top
(
input wire clk,
output wire led
);
blink #(
.CLK_SPEED(27_000_000)
) blink_inst (
.clk(clk),
.led(led)
);
endmodule

View File

@@ -0,0 +1,71 @@
`timescale 1ns/1ps
`default_nettype none
// Simple counter_reg with synchronous reset (and no load)
//
module counter #(
parameter WIDTH = 8,
parameter INITIAL_VALUE = 8'h0f
) (
input wire clk, // global clock
input wire reset, // synchronous reset signal
input wire en, // enable signal
output reg strobe // output strobe
);
initial strobe = 0;
reg[WIDTH-1:0] counter_reg = INITIAL_VALUE;
always @(posedge clk) begin
if (reset) begin
counter_reg <= INITIAL_VALUE;
end
else if (en) begin
strobe <= 0;
if (counter_reg == 0)
counter_reg <= INITIAL_VALUE;
else begin
if (counter_reg == 1)
strobe <= 1;
counter_reg <= counter_reg - 1;
end
end
end
`ifdef FORMAL
reg f_past_valid = 0;
always @* f_past_valid = !$initstate;
always @* begin
assume (counter_reg <= INITIAL_VALUE);
end
always @(posedge clk) begin
// if ($initstate) begin
// assume(counter_reg==INITIAL_VALUE);
// end
// if (!$initstate && $past(en)==1 && !$past(reset)) begin
if (f_past_valid && $past(en)==1 && !$past(reset)) begin
if (counter_reg < INITIAL_VALUE)
assert (counter_reg == $past(counter_reg) - 1);
else begin
assert(counter_reg == INITIAL_VALUE && $past(counter_reg)==0);
end
end
end
`endif
`ifdef VERIFIC
//internal_check: assert property (@(posedge clk)(counter_reg==11)|=>(counter_reg==10));
//assert property (@(posedge clk)(counter_reg==11 && en && !reset)|=>(counter_reg==10));
`endif
endmodule

View File

@@ -0,0 +1,96 @@
import cocotb
from cocotb.triggers import Timer, RisingEdge, First
# from cocotb.triggers import FallingEdge, RisingEdge, First, Timer, Event
from cocotb_test.simulator import run
import pytest
import os
async def generate_clock(dut):
"""Generate clock pulses."""
# for cycle in range(100):
while True:
dut.clk.value = 0
await Timer(5, "ns")
dut.clk.value = 1
await Timer(5, "ns")
@cocotb.test()
async def counter_simple_test(dut):
await cocotb.start(generate_clock(dut)) # run the clock "in the background"
#dut._log.info("my_signal_1 is %s", dut.my_signal_1.value)
# await Timer(10000, units='ns')
#for i in range(dut.WRITE_NB.value):
# await RisingEdge(dut.write_transaction)
#for i in range(dut.READ_NB.value):
# await RisingEdge(dut.read_transaction)
#await Timer(400, units="ns")
await RisingEdge(dut.clk)
dut.reset.value = 1
await RisingEdge(dut.clk)
dut.reset.value = 0
dut.en.value = 1
await Timer(400, units="ns")
await RisingEdge(dut.clk)
dut.en.value = 0
await Timer(50, units="ns")
await RisingEdge(dut.clk)
dut.en.value = 1
await Timer(500, units="ns")
# assert strobe : have a new process counting strobes
def test_counter_runner():
current_dir = os.path.dirname(__file__)
root = "{current_dir}../.."
print(f"root: {root}")
run(
# python_search=[os.path.join(current_dir, "../cocotb/")],
python_search=[current_dir],
verilog_sources=[
f"{root}/src/verilog/counter.v",
], # sources
toplevel="counter", # top level HDL
module="counter_test", # name of cocotb test module
sim_build=f"{root}/runs/cocotb", # + "_".join(("{}={}".format(*i) for i in parameters.items())),
# parameters = parameters,
waves=1,
)
@pytest.mark.skipif(os.getenv("SIM") == "verilator", reason="Custom for verilator")
@pytest.mark.parametrize("parameters", [{"WIDTH": 4, "INITIAL_VALUE": 5}, {"WIDTH": 8, "INITIAL_VALUE": 15}, {"WIDTH": 8, "INITIAL_VALUE": 255}])
def test_parametrized_counter_runner(parameters):
current_dir = os.path.dirname(__file__)
#from pathlib import Path
#proj_path = Path(__file__).resolve().parent
root = "{current_dir}../.."
run(
# python_search=[os.path.join(current_dir, "../cocotb/")],
python_search=[current_dir],
verilog_sources=[
f"{root}/src/verilog/counter.v",
], # sources
toplevel="counter", # top level HDL
module="counter_test", # name of cocotb test module
sim_build=f"{root}/runs/cocotb/" + "_".join(("{}={}".format(*i) for i in parameters.items())),
parameters = parameters,
waves=1,
)
if __name__ == "__main__":
test_counter_runner()

View File

@@ -0,0 +1,37 @@
`timescale 1ns/1ps
`default_nettype none
module blink_tb ();
reg clk = 0;
initial forever #5 clk = !clk;
wire led;
blink #(.CLK_SPEED(20)) bl (.clk(clk),.led(led));
initial begin
`ifdef VCD_DUMP
$dumpfile("blink_tb.vcd");
$dumpvars(0,blink_tb);
`endif
end
initial begin
`ifdef END_TIME
#`END_TIME $finish();
`else
#1000 $finish();
`endif
end
initial begin
#500 $finish();
end
endmodule

View File

@@ -0,0 +1,27 @@
[tasks]
bmc
prove
cover
[options]
bmc: mode bmc
prove: mode prove
cover: mode cover
bmc: depth 100
[engines]
smtbmc
#smtbmc z3
#abc bmc3
[script]
read -verific
read -sv counter.v
read -formal counter_formal.sv
prep -top counter
[files]
../src/verilog/counter.v
counter_formal.sv

View File

@@ -0,0 +1,48 @@
`default_nettype none
module counter_formal (
input wire clk, // global clock
input wire reset, // synchronous reset signal
(*anyseq*) input wire en, // enable signal
input wire strobe, // output strobe
input wire [counter.WIDTH-1:0] counter_reg
);
`ifdef VERIFIC
internal_check: assert property (@(posedge clk)
disable iff (reset)
en && (counter_reg==11)|=>(counter_reg==10)) ;
decrease_enable_check: assert property (@(posedge clk)
disable iff (reset || !en)
(counter_reg >0 ) |=> (counter_reg == $past(counter_reg) - 1));
roll_enable_check: assert property (@(posedge clk)
disable iff (reset || !en)
(counter_reg == 0 ) |=> (counter_reg == counter.INITIAL_VALUE));
max_value_assert_check: assert property (
@(posedge clk)
(counter_reg <= counter.INITIAL_VALUE)
);
cover_0: cover property(
@(posedge clk)
(counter_reg == 0)
);
cover_2stb: cover property(
@(posedge clk)
(strobe == 1) |-> ##[+] (strobe == 1)
);
`endif
endmodule
bind counter counter_formal counter_f_inst(.*);
//testing: assert property (@(posedge clk)(counter_reg==111)|=>(counter_reg==10));

View File

@@ -0,0 +1,4 @@
runs
.vscode
workspace.code-workspace
*.pyc

View File

@@ -0,0 +1,4 @@
IO_LOC "led" 15;
IO_PORT "led" PULL_MODE=UP DRIVE=8 BANK_VCCIO=1.8;
IO_LOC "clk" 4;
IO_PORT "clk" PULL_MODE=UP BANK_VCCIO=1.8;

View File

@@ -0,0 +1,2 @@
@call c:\tools\oss-cad-suite\environment.bat
@tclsh scripts\project.tcl %*

View File

@@ -0,0 +1,3 @@
sv work ../tests/verilog/blink_tb.v
sv work ../src/verilog/blink.v -i src/verilog
sv work ../src/verilog/counter.v -i src/verilog

View File

@@ -0,0 +1,18 @@
rem @echo off
set PATH=%PATH%;c:\Xilinx\Vivado\2023.2\bin
set top=blink_tb
if not exist output mkdir output
rem call xvlog %FILES%
rem IF %ERRORLEVEL% NEQ 0 goto end
rem call xelab -debug typical %top% -s top_sim
echo Calling XELAB...
call xelab -nolog -prj project\blink.prj -debug typical %top% -s top_sim --override_timeunit --override_timeprecision --timescale 1ns/1ps
rem IF %ERRORLEVEL% NEQ 0 goto end
rem call xsim top_sim -t xsim_run.tcl
echo Calling XSIM...
call xsim top_sim -nolog -R --wdb output/top_sim.wdb
start gtkwave %top%.vcd %top%.gtkw --script gtk_wave_all_signals.tcl
del xsim.jou
del xelab.pb
del webtalk*
:end

View File

@@ -0,0 +1,20 @@
puts "Starting TCL script"
#set path test1b_tb
#gtkwave::forceOpenTreeNode $path
set nfacs [ gtkwave::getNumFacs ]
puts "There are $nfacs signals"
set l [list]
for {set i 0} {$i < $nfacs } {incr i} {
set facname [ gtkwave::getFacName $i ]
set numdots [ expr {[llength [split $facname .]] - 1}]
# puts "$numdots"
if {$numdots == 1} {
lappend l "$facname"
puts "Added signal $facname"
}
}
set num_added [ gtkwave::addSignalsFromList $l ]
gtkwave::setZoomRangeTimes [ gtkwave::getMinTime ] [ gtkwave::getMaxTime ]
puts "Start time [ gtkwave::getMinTime ] end time: [ gtkwave::getMaxTime ]"

View File

@@ -0,0 +1,184 @@
# Tcl launcher script for the project
namespace eval project_launcher {
# Help information for this script
proc print_help {} {
variable script_file "project.tcl"
puts "\nDescription:"
puts "Perform actions related to this project.\n"
puts "Syntax:"
puts "$script_file"
puts "$script_file \[action\] \[args\]"
puts "Usage:"
puts "Name Description"
puts "-------------------------------------------------------------------------"
puts "\[action\] Determine the action to be performed. Default value: help\n"
puts " Current actions: help, clean, sim, verify, test, view, elaborate\n"
puts "\[args\] Arguments related to the action.\n"
puts " --root <dir> changes the root reference for the project.\n"
puts "-------------------------------------------------------------------------\n"
exit 0
}
proc do_clean { root_dir } {
variable dir "$root_dir/runs"
puts "Cleaning all files in directory $dir...\n"
# Checking if the folder is empty to avoid error
if {[catch { glob "$dir/*" } result] != 1} {
file delete -force -- {*}[glob "$dir/*" ]
}
}
proc do_sim_icarus { root_dir verbose } {
# Checking if the folder is empty to avoid error
if {[file exists "$root_dir/scripts/run_iverilog.tcl"] == 1} {
#global root_dir_loc $root_dir
#source $root_dir/scripts/run_iverilog.tcl
try {
set results [exec tclsh $root_dir/scripts/run_iverilog.tcl $root_dir ]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
if {$status != 0} {
puts "Problem running the script :"
puts $results
return
}
if {[expr $verbose]} {
# output the result of the execution
puts $results
}
} else {
puts "The script run_iverilog.tcl does not exist in $root_dir/scripts"
}
}
proc do_sim_pytest { root_dir verbose } {
exec pytest $root_dir/tests/ >@stdout 2>@stderr
}
proc do_elaborate { root_dir } {
exec $root_dir/scripts/run_elaborate.bat
}
proc do_formal { root_dir } {
# We suppose that the sby file is meant to be run from the inside of the folder
# hence we cd there
if {[file pathtype $root_dir] != "absolute"} {
set root_dir "../$root_dir"
}
#set root_dir [file normalize $root_dir]
cd verification
#variable fname [glob -nocomplain $root_dir/verification/*.sby]
variable fname [glob -nocomplain *.sby]
if {[llength $fname]} {
set fname [lindex $fname 0]
puts "Using $fname file..."
exec sby -f $fname --prefix $root_dir/runs/verification/counter >@stdout 2>@stderr
} else {
puts "There are no .sby files present..."
cd ..
return
}
cd ..
}
proc do_view { root_dir } {
# Checking if the folder is empty to avoid error
if {[file exists "$root_dir/scripts/run_gtkwave.tcl"] == 1} {
try {
set results [exec tclsh $root_dir/scripts/run_gtkwave.tcl $root_dir ]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
if {$status != 0} {
puts "Problem running the script :"
puts $results
return
}
} else {
puts "The script run_gtkwave.tcl does not exist in $root_dir/scripts"
}
}
proc main {} {
variable root_dir
# Set the reference directory to where the script is
#set root_dir [file dirname [info script]]
# Set the reference directory for source file relative paths (by default the value is script directory path)
set root_dir "."
# Use origin directory path location variable, if specified in the tcl shell
if { [info exists ::root_dir_loc] } {
set root_dir $::root_dir_loc
}
variable action "help"
variable verbose false
if { $::argc > 0 } {
for {set i 0} {$i < $::argc} {incr i} {
set option [string trim [lindex $::argv $i]]
switch -regexp -- $option {
"--root" { incr i; set root_dir [lindex $::argv $i] }
"--help" { print_help }
"help" { print_help }
"clean" { set action "clean" }
"sim" {incr i; set action "sim_[lindex $::argv $i]" }
"--verbose" { set verbose true }
"-v" { set verbose true }
{pytest|cocotb|test} {set action "pytest"}
{formal|verify|verification} {set action "formal"}
{view} {set action "view"}
{elaborate} {set action "elaborate"}
default {
if { [regexp {^-} $option] } {
puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n"
return 1
}
}
}
}
} else {
print_help
}
puts "Script started. The root dir is $root_dir. The action is: $action\n"
switch -regexp -- $action {
"clean" { do_clean $root_dir }
{sim_icarus|^sim_$|sim_iverilog} { do_sim_icarus $root_dir $verbose}
{sim_cocotb|pytest} { do_sim_pytest $root_dir $verbose}
"formal" { do_formal $root_dir}
"view" {do_view $root_dir}
"elaborate" {do_elaborate $root_dir}
}
}
main
}

View File

@@ -0,0 +1,16 @@
@echo off
rem https://github.com/YosysHQ/apicula
set file_name=src\verilog\counter.v src\verilog\blink.v src\verilog\blink_top.v
set constraints_file=constraints\blink_led.cst
yosys -p "read_verilog -sv %file_name%; synth_gowin -json runs\blink_led_c.json"
set DEVICE=GW2AR-LV18QN88C8/I7
set BOARD=tangnano20k
nextpnr-himbaechel --json runs\blink_led_c.json --write runs\pnr_blink_led.json --device %DEVICE% --vopt cst=%constraints_file% --vopt family=GW2A-18C
gowin_pack -d %DEVICE% -o runs\blink_led_c.fs runs\pnr_blink_led.json
rem openfpgaloader -b %BOARD% blink_led_c.fs

View File

@@ -0,0 +1,88 @@
# Tcl script for iverilog simulation
namespace eval gtkwave {
# Help information for this script
proc print_help {} {
variable script_file "run_gtkwave.tcl"
puts "\nDescription:"
puts "Runs the iverilog simulation.\n"
puts "Syntax:"
puts "$script_file"
puts "$script_file \[action\] \[args\]"
puts "Usage:"
puts "Name Description"
puts "-------------------------------------------------------------------------"
puts "\[action\] Determine the action to be performed. Default value: help\n"
puts " Current actions: help, clean\n"
puts "\[args\] Arguments related to the action.\n"
puts " --root <dir> changes the root reference for the project.\n"
puts "-------------------------------------------------------------------------\n"
exit 0
}
proc main {} {
variable root_dir
# Set the reference directory to where the script is
#set root_dir [file dirname [info script]]
# Set the reference directory for source file relative paths (by default the value is script directory path)
set root_dir "."
if { [info exists ::root_dir_loc] } {
set root_dir $::root_dir_loc
}
if { $::argc > 0 } {
set root_dir [lindex $::argv 0]
}
puts "Starting gtkwave. The root dir is: $root_dir"
# variable root [file dirname [file normalize [info script]]]
# variable root [file dirname [file dirname [info script]]]
variable root $root_dir
variable view_file $root/runs/sim/iverilog/blink_tb.vcd
variable gtkwave_script $root/scripts/gtk_wave_all_signals.tcl
proc run_view {res} {
set name [file rootname $res]
# set iverilog_args "$sim_iverilog::additional_options -g2012 -Wall -I $sim_iverilog::source_path -Y .sv -y $sim_iverilog::source_path -o $sim_iverilog::output_dir/$name.vvp $sim_iverilog::tb_path/$tb $sim_iverilog::sources_full_path"
#set gtkwave_args "-S $gtkwave::gtkwave_script $gtkwave::view_file"
set gtkwave_args "$gtkwave::view_file"
#puts $gtkwave_args
try {
set results [exec gtkwave {*}$gtkwave_args]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
if {$status != 0} {
puts "Problem running gtkwave :"
puts $results
return
}
# output iverilog result
puts $results
}
run_view $root_dir
exit 0
}
# run main
main
}

View File

@@ -0,0 +1,133 @@
# Tcl script for iverilog simulation
namespace eval sim_iverilog {
# Help information for this script
proc print_help {} {
variable script_file "run_iverilog.tcl"
puts "\nDescription:"
puts "Runs the iverilog simulation.\n"
puts "Syntax:"
puts "$script_file"
puts "$script_file \[action\] \[args\]"
puts "Usage:"
puts "Name Description"
puts "-------------------------------------------------------------------------"
puts "\[action\] Determine the action to be performed. Default value: help\n"
puts " Current actions: help, clean\n"
puts "\[args\] Arguments related to the action.\n"
puts " --root <dir> changes the root reference for the project.\n"
puts "-------------------------------------------------------------------------\n"
exit 0
}
proc main {} {
variable root_dir
# Set the reference directory to where the script is
#set root_dir [file dirname [info script]]
# Set the reference directory for source file relative paths (by default the value is script directory path)
set root_dir "."
if { [info exists ::root_dir_loc] } {
set root_dir $::root_dir_loc
}
if { $::argc > 0 } {
set root_dir [lindex $::argv 0]
}
puts "Starting simulation using iverilog. The root dir is: $root_dir"
# variable root [file dirname [file normalize [info script]]]
# variable root [file dirname [file dirname [info script]]]
variable root $root_dir
variable source_path $root/src/verilog
variable sources {blink.v}
variable tb_path $root/tests/verilog
variable test_benches {blink_tb.v}
proc append_path {root list} {
set l {}
foreach f $list {
lappend l $root/$f
}
return $l
}
variable sources_full_path [append_path $source_path $sources]
variable tb_full_path [append_path $tb_path $test_benches]
variable output_dir $root/runs/sim/iverilog
variable additional_options "-D VCD_DUMP"
proc run_sim {tb} {
set name [file rootname $tb]
puts "Running test bench $name"
puts "Cleaning files..."
# file delete [glob -nocomplain $sim_iverilog::output_dir/*]
puts "Recreating path..."
file mkdir $sim_iverilog::output_dir
set iverilog_args "$sim_iverilog::additional_options -g2012 -Wall -I $sim_iverilog::source_path -Y .sv -y $sim_iverilog::source_path -o $sim_iverilog::output_dir/$name.vvp $sim_iverilog::tb_path/$tb $sim_iverilog::sources_full_path"
try {
set results [exec iverilog {*}$iverilog_args]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
if {$status != 0} {
puts "Problem running iverilog :"
puts $results
return
}
# output iverilog result
puts $results
set cwd [pwd]
puts "Running vvp..."
set vvp_cmd "vvp $name.vvp -lxt2"
cd $sim_iverilog::output_dir
#puts [pwd]
set results [exec {*}$vvp_cmd]
# output vvp result
puts $results
cd $cwd
puts "All done..."
}
foreach tb $test_benches {
run_sim $tb
}
exit 0
}
# run main
main
}

View File

@@ -0,0 +1,34 @@
`timescale 1ns/1ps
`default_nettype none
module blink #(
parameter CLK_SPEED = 27_000_000
)
(
input wire clk,
output reg led
);
wire strobe;
localparam ONE_HALF_S = CLK_SPEED / 2;
localparam ONE_S = CLK_SPEED ;
localparam TWO_S = CLK_SPEED *2;
localparam TIME = TWO_S;
localparam TIME_WIDTH = $clog2(TIME);
initial led = 0;
counter #(.WIDTH(TIME_WIDTH), .INITIAL_VALUE(TIME)) counter_inst
(
.clk(clk),
.reset(1'b0),
.en(1'b1),
.strobe(strobe)
);
always_ff @(posedge clk)
if(strobe) led <= !led;
endmodule

View File

@@ -0,0 +1,14 @@
module blink_top
(
input wire clk,
output wire led
);
blink #(
.CLK_SPEED(27_000_000)
) blink_inst (
.clk(clk),
.led(led)
);
endmodule

View File

@@ -0,0 +1,71 @@
`timescale 1ns/1ps
`default_nettype none
// Simple counter_reg with synchronous reset (and no load)
//
module counter #(
parameter WIDTH = 8,
parameter INITIAL_VALUE = 8'h0f
) (
input wire clk, // global clock
input wire reset, // synchronous reset signal
input wire en, // enable signal
output reg strobe // output strobe
);
initial strobe = 0;
reg[WIDTH-1:0] counter_reg = INITIAL_VALUE;
always @(posedge clk) begin
if (reset) begin
counter_reg <= INITIAL_VALUE;
end
else if (en) begin
strobe <= 0;
if (counter_reg == 0)
counter_reg <= INITIAL_VALUE;
else begin
if (counter_reg == 1)
strobe <= 1;
counter_reg <= counter_reg - 1;
end
end
end
`ifdef FORMAL
reg f_past_valid = 0;
always @* f_past_valid = !$initstate;
always @* begin
assume (counter_reg <= INITIAL_VALUE);
end
always @(posedge clk) begin
// if ($initstate) begin
// assume(counter_reg==INITIAL_VALUE);
// end
// if (!$initstate && $past(en)==1 && !$past(reset)) begin
if (f_past_valid && $past(en)==1 && !$past(reset)) begin
if (counter_reg < INITIAL_VALUE)
assert (counter_reg == $past(counter_reg) - 1);
else begin
assert(counter_reg == INITIAL_VALUE && $past(counter_reg)==0);
end
end
end
`endif
`ifdef VERIFIC
//internal_check: assert property (@(posedge clk)(counter_reg==11)|=>(counter_reg==10));
//assert property (@(posedge clk)(counter_reg==11 && en && !reset)|=>(counter_reg==10));
`endif
endmodule

View File

@@ -0,0 +1,37 @@
`timescale 1ns/1ps
`default_nettype none
module blink_tb ();
reg clk = 0;
initial forever #5 clk = !clk;
wire led;
blink #(.CLK_SPEED(20)) bl (.clk(clk),.led(led));
initial begin
`ifdef VCD_DUMP
$dumpfile("blink_tb.vcd");
$dumpvars(0,blink_tb);
`endif
end
initial begin
`ifdef END_TIME
#`END_TIME $finish();
`else
#1000 $finish();
`endif
end
initial begin
#500 $finish();
end
endmodule

View File

@@ -0,0 +1,27 @@
[tasks]
bmc
prove
cover
[options]
bmc: mode bmc
prove: mode prove
cover: mode cover
bmc: depth 100
[engines]
smtbmc
#smtbmc z3
#abc bmc3
[script]
read -verific
read -sv counter.v
read -formal counter_formal.sv
prep -top counter
[files]
../src/verilog/counter.v
counter_formal.sv

View File

@@ -0,0 +1,48 @@
`default_nettype none
module counter_formal (
input wire clk, // global clock
input wire reset, // synchronous reset signal
(*anyseq*) input wire en, // enable signal
input wire strobe, // output strobe
input wire [counter.WIDTH-1:0] counter_reg
);
`ifdef VERIFIC
internal_check: assert property (@(posedge clk)
disable iff (reset)
en && (counter_reg==11)|=>(counter_reg==10)) ;
decrease_enable_check: assert property (@(posedge clk)
disable iff (reset || !en)
(counter_reg >0 ) |=> (counter_reg == $past(counter_reg) - 1));
roll_enable_check: assert property (@(posedge clk)
disable iff (reset || !en)
(counter_reg == 0 ) |=> (counter_reg == counter.INITIAL_VALUE));
max_value_assert_check: assert property (
@(posedge clk)
(counter_reg <= counter.INITIAL_VALUE)
);
cover_0: cover property(
@(posedge clk)
(counter_reg == 0)
);
cover_2stb: cover property(
@(posedge clk)
(strobe == 1) |-> ##[+] (strobe == 1)
);
`endif
endmodule
bind counter counter_formal counter_f_inst(.*);
//testing: assert property (@(posedge clk)(counter_reg==111)|=>(counter_reg==10));

View File

@@ -0,0 +1,7 @@
0.7
2020.2
Oct 13 2023
20:47:58
c:/ver/roots/programming/FPGA/presentation_examples/blink_vivado/src/verilog/blink.v,1745688175,systemVerilog,,,,blink,,,src/verilog,,,,,
c:/ver/roots/programming/FPGA/presentation_examples/blink_vivado/src/verilog/counter.v,1678724585,systemVerilog,,,,counter,,,src/verilog,,,,,
c:/ver/roots/programming/FPGA/presentation_examples/blink_vivado/tests/verilog/blink_tb.v,1745687036,systemVerilog,,,,blink_tb,,,,,,,,

View File

@@ -0,0 +1,4 @@
runs
.vscode
workspace.code-workspace
*.pyc

View File

@@ -0,0 +1,2 @@
@call c:\tools\oss-cad-suite\environment.bat
@tclsh scripts\project.tcl %*

View File

@@ -0,0 +1,20 @@
puts "Starting TCL script"
#set path test1b_tb
#gtkwave::forceOpenTreeNode $path
set nfacs [ gtkwave::getNumFacs ]
puts "There are $nfacs signals"
set l [list]
for {set i 0} {$i < $nfacs } {incr i} {
set facname [ gtkwave::getFacName $i ]
set numdots [ expr {[llength [split $facname .]] - 1}]
# puts "$numdots"
if {$numdots == 1} {
lappend l "$facname"
puts "Added signal $facname"
}
}
set num_added [ gtkwave::addSignalsFromList $l ]
gtkwave::setZoomRangeTimes [ gtkwave::getMinTime ] [ gtkwave::getMaxTime ]
puts "Start time [ gtkwave::getMinTime ] end time: [ gtkwave::getMaxTime ]"

View File

@@ -0,0 +1,176 @@
# Tcl launcher script for the project
namespace eval project_launcher {
# Help information for this script
proc print_help {} {
variable script_file "project.tcl"
puts "\nDescription:"
puts "Perform actions related to this project.\n"
puts "Syntax:"
puts "$script_file"
puts "$script_file \[action\] \[args\]"
puts "Usage:"
puts "Name Description"
puts "-------------------------------------------------------------------------"
puts "\[action\] Determine the action to be performed. Default value: help\n"
puts " Current actions: help, clean, sim, verify, test, view\n"
puts "\[args\] Arguments related to the action.\n"
puts " --root <dir> changes the root reference for the project.\n"
puts "-------------------------------------------------------------------------\n"
exit 0
}
proc do_clean { root_dir } {
variable dir "$root_dir/runs"
puts "Cleaning all files in directory $dir...\n"
# Checking if the folder is empty to avoid error
if {[catch { glob "$dir/*" } result] != 1} {
file delete -force -- {*}[glob "$dir/*" ]
}
}
proc do_sim_icarus { root_dir verbose } {
# Checking if the folder is empty to avoid error
if {[file exists "$root_dir/scripts/run_iverilog.tcl"] == 1} {
#global root_dir_loc $root_dir
#source $root_dir/scripts/run_iverilog.tcl
try {
set results [exec tclsh $root_dir/scripts/run_iverilog.tcl $root_dir ]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
if {$status != 0} {
puts "Problem running the script :"
puts $results
return
}
if {[expr $verbose]} {
# output the result of the execution
puts $results
}
} else {
puts "The script run_iverilog.tcl does not exist in $root_dir/scripts"
}
}
proc do_sim_pytest { root_dir verbose } {
exec pytest $root_dir/tests/ >@stdout 2>@stderr
}
proc do_formal { root_dir } {
# We suppose that the sby file is meant to be run from the inside of the folder
# hence we cd there
if {[file pathtype $root_dir] != "absolute"} {
set root_dir "../$root_dir"
}
#set root_dir [file normalize $root_dir]
cd verification
#variable fname [glob -nocomplain $root_dir/verification/*.sby]
variable fname [glob -nocomplain *.sby]
if {[llength $fname]} {
set fname [lindex $fname 0]
puts "Using $fname file..."
exec sby -f $fname --prefix $root_dir/runs/verification/counter >@stdout 2>@stderr
} else {
puts "There are no .sby files present..."
cd ..
return
}
cd ..
}
proc do_view { root_dir } {
# Checking if the folder is empty to avoid error
if {[file exists "$root_dir/scripts/run_gtkwave.tcl"] == 1} {
try {
set results [exec tclsh $root_dir/scripts/run_gtkwave.tcl $root_dir ]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
if {$status != 0} {
puts "Problem running the script :"
puts $results
return
}
} else {
puts "The script run_gtkwave.tcl does not exist in $root_dir/scripts"
}
}
proc main {} {
variable root_dir
# Set the reference directory to where the script is
#set root_dir [file dirname [info script]]
# Set the reference directory for source file relative paths (by default the value is script directory path)
set root_dir "."
# Use origin directory path location variable, if specified in the tcl shell
if { [info exists ::root_dir_loc] } {
set root_dir $::root_dir_loc
}
variable action "help"
variable verbose false
if { $::argc > 0 } {
for {set i 0} {$i < $::argc} {incr i} {
set option [string trim [lindex $::argv $i]]
switch -regexp -- $option {
"--root" { incr i; set root_dir [lindex $::argv $i] }
"--help" { print_help }
"help" { print_help }
"clean" { set action "clean" }
"sim" {incr i; set action "sim_[lindex $::argv $i]" }
"--verbose" { set verbose true }
"-v" { set verbose true }
{pytest|cocotb|test} {set action "pytest"}
{formal|verify|verification} {set action "formal"}
{view} {set action "view"}
default {
if { [regexp {^-} $option] } {
puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n"
return 1
}
}
}
}
} else {
print_help
}
puts "Script started. The root dir is $root_dir. The action is: $action\n"
switch -regexp -- $action {
"clean" { do_clean $root_dir }
{sim_icarus|^sim_$|sim_iverilog} { do_sim_icarus $root_dir $verbose}
{sim_cocotb|pytest} { do_sim_pytest $root_dir $verbose}
"formal" { do_formal $root_dir}
"view" {do_view $root_dir}
}
}
main
}

View File

@@ -0,0 +1,88 @@
# Tcl script for iverilog simulation
namespace eval gtkwave {
# Help information for this script
proc print_help {} {
variable script_file "run_gtkwave.tcl"
puts "\nDescription:"
puts "Runs the iverilog simulation.\n"
puts "Syntax:"
puts "$script_file"
puts "$script_file \[action\] \[args\]"
puts "Usage:"
puts "Name Description"
puts "-------------------------------------------------------------------------"
puts "\[action\] Determine the action to be performed. Default value: help\n"
puts " Current actions: help, clean\n"
puts "\[args\] Arguments related to the action.\n"
puts " --root <dir> changes the root reference for the project.\n"
puts "-------------------------------------------------------------------------\n"
exit 0
}
proc main {} {
variable root_dir
# Set the reference directory to where the script is
#set root_dir [file dirname [info script]]
# Set the reference directory for source file relative paths (by default the value is script directory path)
set root_dir "."
if { [info exists ::root_dir_loc] } {
set root_dir $::root_dir_loc
}
if { $::argc > 0 } {
set root_dir [lindex $::argv 0]
}
puts "Starting gtkwave. The root dir is: $root_dir"
# variable root [file dirname [file normalize [info script]]]
# variable root [file dirname [file dirname [info script]]]
variable root $root_dir
variable view_file $root/runs/sim/iverilog/counter_tb.vcd
variable gtkwave_script $root/scripts/gtk_wave_all_signals.tcl
proc run_view {res} {
set name [file rootname $res]
# set iverilog_args "$sim_iverilog::additional_options -g2012 -Wall -I $sim_iverilog::source_path -Y .sv -y $sim_iverilog::source_path -o $sim_iverilog::output_dir/$name.vvp $sim_iverilog::tb_path/$tb $sim_iverilog::sources_full_path"
#set gtkwave_args "-S $gtkwave::gtkwave_script $gtkwave::view_file"
set gtkwave_args "$gtkwave::view_file"
#puts $gtkwave_args
try {
set results [exec gtkwave {*}$gtkwave_args]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
if {$status != 0} {
puts "Problem running gtkwave :"
puts $results
return
}
# output iverilog result
puts $results
}
run_view $root_dir
exit 0
}
# run main
main
}

View File

@@ -0,0 +1,133 @@
# Tcl script for iverilog simulation
namespace eval sim_iverilog {
# Help information for this script
proc print_help {} {
variable script_file "run_iverilog.tcl"
puts "\nDescription:"
puts "Runs the iverilog simulation.\n"
puts "Syntax:"
puts "$script_file"
puts "$script_file \[action\] \[args\]"
puts "Usage:"
puts "Name Description"
puts "-------------------------------------------------------------------------"
puts "\[action\] Determine the action to be performed. Default value: help\n"
puts " Current actions: help, clean\n"
puts "\[args\] Arguments related to the action.\n"
puts " --root <dir> changes the root reference for the project.\n"
puts "-------------------------------------------------------------------------\n"
exit 0
}
proc main {} {
variable root_dir
# Set the reference directory to where the script is
#set root_dir [file dirname [info script]]
# Set the reference directory for source file relative paths (by default the value is script directory path)
set root_dir "."
if { [info exists ::root_dir_loc] } {
set root_dir $::root_dir_loc
}
if { $::argc > 0 } {
set root_dir [lindex $::argv 0]
}
puts "Starting simulation using iverilog. The root dir is: $root_dir"
# variable root [file dirname [file normalize [info script]]]
# variable root [file dirname [file dirname [info script]]]
variable root $root_dir
variable source_path $root/src/verilog
variable sources {counter.v}
variable tb_path $root/tests/verilog
variable test_benches {counter_tb.v}
proc append_path {root list} {
set l {}
foreach f $list {
lappend l $root/$f
}
return $l
}
variable sources_full_path [append_path $source_path $sources]
variable tb_full_path [append_path $tb_path $test_benches]
variable output_dir $root/runs/sim/iverilog
variable additional_options "-D VCD_DUMP"
proc run_sim {tb} {
set name [file rootname $tb]
puts "Running test bench $name"
puts "Cleaning files..."
# file delete [glob -nocomplain $sim_iverilog::output_dir/*]
puts "Recreating path..."
file mkdir $sim_iverilog::output_dir
set iverilog_args "$sim_iverilog::additional_options -g2012 -Wall -I $sim_iverilog::source_path -Y .sv -y $sim_iverilog::source_path -o $sim_iverilog::output_dir/$name.vvp $sim_iverilog::tb_path/$tb $sim_iverilog::sources_full_path"
try {
set results [exec iverilog {*}$iverilog_args]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
if {$status != 0} {
puts "Problem running iverilog :"
puts $results
return
}
# output iverilog result
puts $results
set cwd [pwd]
puts "Running vvp..."
set vvp_cmd "vvp $name.vvp -lxt2"
cd $sim_iverilog::output_dir
#puts [pwd]
set results [exec {*}$vvp_cmd]
# output vvp result
puts $results
cd $cwd
puts "All done..."
}
foreach tb $test_benches {
run_sim $tb
}
exit 0
}
# run main
main
}

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