mirror of https://github.com/YosysHQ/yosys.git
This commit is contained in:
commit
0d7e71f7ab
2
Makefile
2
Makefile
|
@ -86,7 +86,7 @@ OBJS = kernel/version_$(GIT_REV).o
|
||||||
# is just a symlink to your actual ABC working directory, as 'make mrproper'
|
# 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
|
# will remove the 'abc' directory and you do not want to accidentally
|
||||||
# delete your work on ABC..
|
# delete your work on ABC..
|
||||||
ABCREV = f8cadfe3861f
|
ABCREV = a2fcd1cc61a6
|
||||||
ABCPULL = 1
|
ABCPULL = 1
|
||||||
ABCURL ?= https://bitbucket.org/alanmi/abc
|
ABCURL ?= https://bitbucket.org/alanmi/abc
|
||||||
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)"
|
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)"
|
||||||
|
|
17
README.md
17
README.md
|
@ -46,7 +46,7 @@ Getting Started
|
||||||
|
|
||||||
You need a C++ compiler with C++11 support (up-to-date CLANG or GCC is
|
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.
|
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).
|
TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile).
|
||||||
Xdot (graphviz) is used by the ``show`` command in yosys to display schematics.
|
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
|
For example on Ubuntu Linux 16.04 LTS the following commands will install all
|
||||||
prerequisites for building yosys:
|
prerequisites for building yosys:
|
||||||
|
@ -372,16 +372,17 @@ Verilog Attributes and non-standard features
|
||||||
Non-standard or SystemVerilog features for formal verification
|
Non-standard or SystemVerilog features for formal verification
|
||||||
==============================================================
|
==============================================================
|
||||||
|
|
||||||
- Support for ``assert``, ``assume``, and ``restrict`` is enabled when
|
- Support for ``assert``, ``assume``, ``restrict``, and ``cover'' is enabled
|
||||||
``read_verilog`` is called with ``-formal``.
|
when ``read_verilog`` is called with ``-formal``.
|
||||||
|
|
||||||
- The system task ``$initstate`` evaluates to 1 in the initial state and
|
- The system task ``$initstate`` evaluates to 1 in the initial state and
|
||||||
to 0 otherwise.
|
to 0 otherwise.
|
||||||
|
|
||||||
- The system task ``$anyconst`` evaluates to any constant value.
|
- The system task ``$anyconst`` evaluates to any constant value. This is
|
||||||
|
equivalent to declaring a reg as ``const rand``.
|
||||||
|
|
||||||
- The system task ``$anyseq`` evaluates to any value, possibly a different
|
- The system task ``$anyseq`` evaluates to any value, possibly a different
|
||||||
value in each cycle.
|
value in each cycle. This is equivalent to declaring a reg as ``rand``.
|
||||||
|
|
||||||
- The SystemVerilog tasks ``$past``, ``$stable``, ``$rose`` and ``$fell`` are
|
- The SystemVerilog tasks ``$past``, ``$stable``, ``$rose`` and ``$fell`` are
|
||||||
supported in any clocked block.
|
supported in any clocked block.
|
||||||
|
@ -400,12 +401,14 @@ from SystemVerilog:
|
||||||
form. In module context: ``assert property (<expression>);`` and within an
|
form. In module context: ``assert property (<expression>);`` and within an
|
||||||
always block: ``assert(<expression>);``. It is transformed to a $assert cell.
|
always block: ``assert(<expression>);``. It is transformed to a $assert cell.
|
||||||
|
|
||||||
- The ``assume`` and ``restrict`` statements from SystemVerilog are also
|
- The ``assume``, ``restrict``, and ``cover`` statements from SystemVerilog are
|
||||||
supported. The same limitations as with the ``assert`` statement apply.
|
also supported. The same limitations as with the ``assert`` statement apply.
|
||||||
|
|
||||||
- The keywords ``always_comb``, ``always_ff`` and ``always_latch``, ``logic``
|
- The keywords ``always_comb``, ``always_ff`` and ``always_latch``, ``logic``
|
||||||
and ``bit`` are supported.
|
and ``bit`` are supported.
|
||||||
|
|
||||||
|
- Declaring free variables with ``rand`` and ``const rand`` is supported.
|
||||||
|
|
||||||
- SystemVerilog packages are supported. Once a SystemVerilog file is read
|
- SystemVerilog packages are supported. Once a SystemVerilog file is read
|
||||||
into a design with ``read_verilog``, all its packages are available to
|
into a design with ``read_verilog``, all its packages are available to
|
||||||
SystemVerilog files being read into the same design afterwards.
|
SystemVerilog files being read into the same design afterwards.
|
||||||
|
|
|
@ -662,19 +662,25 @@ struct Smt2Worker
|
||||||
|
|
||||||
if (verbose) log("=> export logic driving asserts\n");
|
if (verbose) log("=> export logic driving asserts\n");
|
||||||
|
|
||||||
vector<string> assert_list, assume_list;
|
vector<string> assert_list, assume_list, cover_list;
|
||||||
for (auto cell : module->cells())
|
for (auto cell : module->cells())
|
||||||
if (cell->type.in("$assert", "$assume")) {
|
if (cell->type.in("$assert", "$assume", "$cover")) {
|
||||||
string name_a = get_bool(cell->getPort("\\A"));
|
string name_a = get_bool(cell->getPort("\\A"));
|
||||||
string name_en = get_bool(cell->getPort("\\EN"));
|
string name_en = get_bool(cell->getPort("\\EN"));
|
||||||
decls.push_back(stringf("; yosys-smt2-%s %s#%d %s\n", cell->type.c_str() + 1, get_id(module), idcounter,
|
decls.push_back(stringf("; yosys-smt2-%s %s#%d %s\n", cell->type.c_str() + 1, get_id(module), idcounter,
|
||||||
cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell)));
|
cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell)));
|
||||||
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool (or %s (not %s))) ; %s\n",
|
if (cell->type == "$cover")
|
||||||
get_id(module), idcounter, get_id(module), name_a.c_str(), name_en.c_str(), get_id(cell)));
|
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n",
|
||||||
|
get_id(module), idcounter, get_id(module), name_a.c_str(), name_en.c_str(), get_id(cell)));
|
||||||
|
else
|
||||||
|
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool (or %s (not %s))) ; %s\n",
|
||||||
|
get_id(module), idcounter, get_id(module), name_a.c_str(), name_en.c_str(), get_id(cell)));
|
||||||
if (cell->type == "$assert")
|
if (cell->type == "$assert")
|
||||||
assert_list.push_back(stringf("(|%s#%d| state)", get_id(module), idcounter++));
|
assert_list.push_back(stringf("(|%s#%d| state)", get_id(module), idcounter++));
|
||||||
else
|
else if (cell->type == "$assume")
|
||||||
assume_list.push_back(stringf("(|%s#%d| state)", get_id(module), idcounter++));
|
assume_list.push_back(stringf("(|%s#%d| state)", get_id(module), idcounter++));
|
||||||
|
else if (cell->type == "$cover")
|
||||||
|
cover_list.push_back(stringf("(|%s#%d| state)", get_id(module), idcounter++));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int iter = 1; !registers.empty(); iter++)
|
for (int iter = 1; !registers.empty(); iter++)
|
||||||
|
|
|
@ -29,11 +29,14 @@ num_steps = 20
|
||||||
append_steps = 0
|
append_steps = 0
|
||||||
vcdfile = None
|
vcdfile = None
|
||||||
cexfile = None
|
cexfile = None
|
||||||
aigprefix = None
|
aimfile = None
|
||||||
|
aiwfile = None
|
||||||
|
aigheader = True
|
||||||
vlogtbfile = None
|
vlogtbfile = None
|
||||||
inconstr = list()
|
inconstr = list()
|
||||||
outconstr = None
|
outconstr = None
|
||||||
gentrace = False
|
gentrace = False
|
||||||
|
covermode = False
|
||||||
tempind = False
|
tempind = False
|
||||||
dumpall = False
|
dumpall = False
|
||||||
assume_skipped = None
|
assume_skipped = None
|
||||||
|
@ -59,6 +62,9 @@ yosys-smtbmc [options] <yosys_smt2_output>
|
||||||
-i
|
-i
|
||||||
instead of BMC run temporal induction
|
instead of BMC run temporal induction
|
||||||
|
|
||||||
|
-c
|
||||||
|
instead of regular BMC run cover analysis
|
||||||
|
|
||||||
-m <module_name>
|
-m <module_name>
|
||||||
name of the top module
|
name of the top module
|
||||||
|
|
||||||
|
@ -73,6 +79,14 @@ yosys-smtbmc [options] <yosys_smt2_output>
|
||||||
and AIGER witness file. The file names are <prefix>.aim for
|
and AIGER witness file. The file names are <prefix>.aim for
|
||||||
the map file and <prefix>.aiw for the witness file.
|
the map file and <prefix>.aiw for the witness file.
|
||||||
|
|
||||||
|
--aig <aim_filename>:<aiw_filename>
|
||||||
|
like above, but for map files and witness files that do not
|
||||||
|
share a filename prefix (or use differen file extensions).
|
||||||
|
|
||||||
|
--aig-noheader
|
||||||
|
the AIGER witness file does not include the status and
|
||||||
|
properties lines.
|
||||||
|
|
||||||
--noinfo
|
--noinfo
|
||||||
only run the core proof, do not collect and print any
|
only run the core proof, do not collect and print any
|
||||||
additional information (e.g. which assert failed)
|
additional information (e.g. which assert failed)
|
||||||
|
@ -110,8 +124,8 @@ yosys-smtbmc [options] <yosys_smt2_output>
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igm:", so.longopts +
|
opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igcm:", so.longopts +
|
||||||
["final-only", "assume-skipped=", "smtc=", "cex=", "aig=",
|
["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader",
|
||||||
"dump-vcd=", "dump-vlogtb=", "dump-smtc=", "dump-all", "noinfo", "append="])
|
"dump-vcd=", "dump-vlogtb=", "dump-smtc=", "dump-all", "noinfo", "append="])
|
||||||
except:
|
except:
|
||||||
usage()
|
usage()
|
||||||
|
@ -140,7 +154,13 @@ for o, a in opts:
|
||||||
elif o == "--cex":
|
elif o == "--cex":
|
||||||
cexfile = a
|
cexfile = a
|
||||||
elif o == "--aig":
|
elif o == "--aig":
|
||||||
aigprefix = a
|
if ":" in a:
|
||||||
|
aimfile, aiwfile = a.split(":")
|
||||||
|
else:
|
||||||
|
aimfile = a + ".aim"
|
||||||
|
aiwfile = a + ".aiw"
|
||||||
|
elif o == "--aig-noheader":
|
||||||
|
aigheader = False
|
||||||
elif o == "--dump-vcd":
|
elif o == "--dump-vcd":
|
||||||
vcdfile = a
|
vcdfile = a
|
||||||
elif o == "--dump-vlogtb":
|
elif o == "--dump-vlogtb":
|
||||||
|
@ -157,6 +177,8 @@ for o, a in opts:
|
||||||
tempind = True
|
tempind = True
|
||||||
elif o == "-g":
|
elif o == "-g":
|
||||||
gentrace = True
|
gentrace = True
|
||||||
|
elif o == "-c":
|
||||||
|
covermode = True
|
||||||
elif o == "-m":
|
elif o == "-m":
|
||||||
topmod = a
|
topmod = a
|
||||||
elif so.handle(o, a):
|
elif so.handle(o, a):
|
||||||
|
@ -167,6 +189,8 @@ for o, a in opts:
|
||||||
if len(args) != 1:
|
if len(args) != 1:
|
||||||
usage()
|
usage()
|
||||||
|
|
||||||
|
if sum([tempind, gentrace, covermode]) > 1:
|
||||||
|
usage()
|
||||||
|
|
||||||
constr_final_start = None
|
constr_final_start = None
|
||||||
constr_asserts = defaultdict(list)
|
constr_asserts = defaultdict(list)
|
||||||
|
@ -375,7 +399,7 @@ if cexfile is not None:
|
||||||
skip_steps = max(skip_steps, step)
|
skip_steps = max(skip_steps, step)
|
||||||
num_steps = max(num_steps, step+1)
|
num_steps = max(num_steps, step+1)
|
||||||
|
|
||||||
if aigprefix is not None:
|
if aimfile is not None:
|
||||||
input_map = dict()
|
input_map = dict()
|
||||||
init_map = dict()
|
init_map = dict()
|
||||||
latch_map = dict()
|
latch_map = dict()
|
||||||
|
@ -385,7 +409,7 @@ if aigprefix is not None:
|
||||||
skip_steps = 0
|
skip_steps = 0
|
||||||
num_steps = 0
|
num_steps = 0
|
||||||
|
|
||||||
with open(aigprefix + ".aim", "r") as f:
|
with open(aimfile, "r") as f:
|
||||||
for entry in f.read().splitlines():
|
for entry in f.read().splitlines():
|
||||||
entry = entry.split()
|
entry = entry.split()
|
||||||
|
|
||||||
|
@ -406,11 +430,14 @@ if aigprefix is not None:
|
||||||
|
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
with open(aigprefix + ".aiw", "r") as f:
|
with open(aiwfile, "r") as f:
|
||||||
got_state = False
|
got_state = False
|
||||||
got_ffinit = False
|
got_ffinit = False
|
||||||
step = 0
|
step = 0
|
||||||
|
|
||||||
|
if not aigheader:
|
||||||
|
got_state = True
|
||||||
|
|
||||||
for entry in f.read().splitlines():
|
for entry in f.read().splitlines():
|
||||||
if len(entry) == 0 or entry[0] in "bcjfu.":
|
if len(entry) == 0 or entry[0] in "bcjfu.":
|
||||||
continue
|
continue
|
||||||
|
@ -458,13 +485,30 @@ if aigprefix is not None:
|
||||||
bitidx = init_map[i][1]
|
bitidx = init_map[i][1]
|
||||||
|
|
||||||
path = smt.get_path(topmod, name)
|
path = smt.get_path(topmod, name)
|
||||||
width = smt.net_width(topmod, path)
|
|
||||||
|
if not smt.net_exists(topmod, path):
|
||||||
|
match = re.match(r"(.*)\[(\d+)\]$", path[-1])
|
||||||
|
if match:
|
||||||
|
path[-1] = match.group(1)
|
||||||
|
addr = int(match.group(2))
|
||||||
|
|
||||||
|
if not match or not smt.mem_exists(topmod, path):
|
||||||
|
print_msg("Ignoring init value for unknown net: %s" % (name))
|
||||||
|
continue
|
||||||
|
|
||||||
|
meminfo = smt.mem_info(topmod, path)
|
||||||
|
smtexpr = "(select [%s] #b%s)" % (".".join(path), bin(addr)[2:].zfill(meminfo[0]))
|
||||||
|
width = meminfo[1]
|
||||||
|
|
||||||
|
else:
|
||||||
|
smtexpr = "[%s]" % name
|
||||||
|
width = smt.net_width(topmod, path)
|
||||||
|
|
||||||
if width == 1:
|
if width == 1:
|
||||||
assert bitidx == 0
|
assert bitidx == 0
|
||||||
smtexpr = "(= [%s] %s)" % (name, "true" if value else "false")
|
smtexpr = "(= %s %s)" % (smtexpr, "true" if value else "false")
|
||||||
else:
|
else:
|
||||||
smtexpr = "(= ((_ extract %d %d) [%s]) #b%d)" % (bitidx, bitidx, name, value)
|
smtexpr = "(= ((_ extract %d %d) %s) #b%d)" % (bitidx, bitidx, smtexpr, value)
|
||||||
|
|
||||||
constr_assumes[0].append((cexfile, smtexpr))
|
constr_assumes[0].append((cexfile, smtexpr))
|
||||||
|
|
||||||
|
@ -569,7 +613,7 @@ def write_vlogtb_trace(steps_start, steps_stop, index):
|
||||||
|
|
||||||
mems = sorted(smt.hiermems(topmod))
|
mems = sorted(smt.hiermems(topmod))
|
||||||
for mempath in mems:
|
for mempath in mems:
|
||||||
abits, width, ports = smt.mem_info(topmod, "s%d" % steps_start, mempath)
|
abits, width, ports = smt.mem_info(topmod, mempath)
|
||||||
mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath)
|
mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath)
|
||||||
|
|
||||||
addr_expr_list = list()
|
addr_expr_list = list()
|
||||||
|
@ -630,7 +674,7 @@ def write_constr_trace(steps_start, steps_stop, index):
|
||||||
|
|
||||||
mems = sorted(smt.hiermems(topmod))
|
mems = sorted(smt.hiermems(topmod))
|
||||||
for mempath in mems:
|
for mempath in mems:
|
||||||
abits, width, ports = smt.mem_info(topmod, "s%d" % steps_start, mempath)
|
abits, width, ports = smt.mem_info(topmod, mempath)
|
||||||
mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath)
|
mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath)
|
||||||
|
|
||||||
addr_expr_list = list()
|
addr_expr_list = list()
|
||||||
|
@ -669,30 +713,40 @@ def write_trace(steps_start, steps_stop, index):
|
||||||
write_constr_trace(steps_start, steps_stop, index)
|
write_constr_trace(steps_start, steps_stop, index)
|
||||||
|
|
||||||
|
|
||||||
def print_failed_asserts_worker(mod, state, path):
|
def print_failed_asserts_worker(mod, state, path, extrainfo):
|
||||||
assert mod in smt.modinfo
|
assert mod in smt.modinfo
|
||||||
|
found_failed_assert = False
|
||||||
|
|
||||||
if smt.get("(|%s_a| %s)" % (mod, state)) in ["true", "#b1"]:
|
if smt.get("(|%s_a| %s)" % (mod, state)) in ["true", "#b1"]:
|
||||||
return
|
return
|
||||||
|
|
||||||
for cellname, celltype in smt.modinfo[mod].cells.items():
|
for cellname, celltype in smt.modinfo[mod].cells.items():
|
||||||
print_failed_asserts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname)
|
if print_failed_asserts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname, extrainfo):
|
||||||
|
found_failed_assert = True
|
||||||
|
|
||||||
for assertfun, assertinfo in smt.modinfo[mod].asserts.items():
|
for assertfun, assertinfo in smt.modinfo[mod].asserts.items():
|
||||||
if smt.get("(|%s| %s)" % (assertfun, state)) in ["false", "#b0"]:
|
if smt.get("(|%s| %s)" % (assertfun, state)) in ["false", "#b0"]:
|
||||||
print_msg("Assert failed in %s: %s" % (path, assertinfo))
|
print_msg("Assert failed in %s: %s%s" % (path, assertinfo, extrainfo))
|
||||||
|
found_failed_assert = True
|
||||||
|
|
||||||
|
return found_failed_assert
|
||||||
|
|
||||||
|
|
||||||
def print_failed_asserts(state, final=False):
|
def print_failed_asserts(state, final=False, extrainfo=""):
|
||||||
if noinfo: return
|
if noinfo: return
|
||||||
loc_list, expr_list, value_list = get_constr_expr(constr_asserts, state, final=final, getvalues=True)
|
loc_list, expr_list, value_list = get_constr_expr(constr_asserts, state, final=final, getvalues=True)
|
||||||
|
found_failed_assert = False
|
||||||
|
|
||||||
for loc, expr, value in zip(loc_list, expr_list, value_list):
|
for loc, expr, value in zip(loc_list, expr_list, value_list):
|
||||||
if smt.bv2int(value) == 0:
|
if smt.bv2int(value) == 0:
|
||||||
print_msg("Assert %s failed: %s" % (loc, expr))
|
print_msg("Assert %s failed: %s%s" % (loc, expr, extrainfo))
|
||||||
|
found_failed_assert = True
|
||||||
|
|
||||||
if not final:
|
if not final:
|
||||||
print_failed_asserts_worker(topmod, "s%d" % state, topmod)
|
if print_failed_asserts_worker(topmod, "s%d" % state, topmod, extrainfo):
|
||||||
|
found_failed_assert = True
|
||||||
|
|
||||||
|
return found_failed_assert
|
||||||
|
|
||||||
|
|
||||||
def print_anyconsts_worker(mod, state, path):
|
def print_anyconsts_worker(mod, state, path):
|
||||||
|
@ -710,6 +764,24 @@ def print_anyconsts(state):
|
||||||
print_anyconsts_worker(topmod, "s%d" % state, topmod)
|
print_anyconsts_worker(topmod, "s%d" % state, topmod)
|
||||||
|
|
||||||
|
|
||||||
|
def get_cover_list(mod, base):
|
||||||
|
assert mod in smt.modinfo
|
||||||
|
|
||||||
|
cover_expr = list()
|
||||||
|
cover_desc = list()
|
||||||
|
|
||||||
|
for expr, desc in smt.modinfo[mod].covers.items():
|
||||||
|
cover_expr.append("(ite (|%s| %s) #b1 #b0)" % (expr, base))
|
||||||
|
cover_desc.append(desc)
|
||||||
|
|
||||||
|
for cell, submod in smt.modinfo[mod].cells.items():
|
||||||
|
e, d = get_cover_list(submod, "(|%s_h %s| %s)" % (mod, cell, base))
|
||||||
|
cover_expr += e
|
||||||
|
cover_desc += d
|
||||||
|
|
||||||
|
return cover_expr, cover_desc
|
||||||
|
|
||||||
|
|
||||||
if tempind:
|
if tempind:
|
||||||
retstatus = False
|
retstatus = False
|
||||||
skip_counter = step_size
|
skip_counter = step_size
|
||||||
|
@ -757,8 +829,92 @@ if tempind:
|
||||||
retstatus = True
|
retstatus = True
|
||||||
break
|
break
|
||||||
|
|
||||||
|
elif covermode:
|
||||||
|
cover_expr, cover_desc = get_cover_list(topmod, "state")
|
||||||
|
cover_mask = "1" * len(cover_desc)
|
||||||
|
|
||||||
else: # not tempind
|
if len(cover_expr) > 1:
|
||||||
|
cover_expr = "(concat %s)" % " ".join(cover_expr)
|
||||||
|
elif len(cover_expr) == 1:
|
||||||
|
cover_expr = cover_expr[0]
|
||||||
|
else:
|
||||||
|
cover_expr = "#b0"
|
||||||
|
|
||||||
|
coveridx = 0
|
||||||
|
smt.write("(define-fun covers_0 ((state |%s_s|)) (_ BitVec %d) %s)" % (topmod, len(cover_desc), cover_expr))
|
||||||
|
|
||||||
|
step = 0
|
||||||
|
retstatus = False
|
||||||
|
found_failed_assert = False
|
||||||
|
|
||||||
|
assert step_size == 1
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
while "1" in cover_mask:
|
||||||
|
print_msg("Checking cover reachability in step %d.." % (step))
|
||||||
|
smt.write("(push 1)")
|
||||||
|
smt.write("(assert (distinct (covers_%d s%d) #b%s))" % (coveridx, step, "0" * len(cover_desc)))
|
||||||
|
|
||||||
|
if smt.check_sat() == "unsat":
|
||||||
|
smt.write("(pop 1)")
|
||||||
|
break
|
||||||
|
|
||||||
|
reached_covers = smt.bv2bin(smt.get("(covers_%d s%d)" % (coveridx, step)))
|
||||||
|
assert len(reached_covers) == len(cover_desc)
|
||||||
|
|
||||||
|
new_cover_mask = []
|
||||||
|
|
||||||
|
for i in range(len(reached_covers)):
|
||||||
|
if reached_covers[i] == "0":
|
||||||
|
new_cover_mask.append(cover_mask[i])
|
||||||
|
continue
|
||||||
|
|
||||||
|
print_msg("Reached cover statement at %s in step %d." % (cover_desc[i], step))
|
||||||
|
new_cover_mask.append("0")
|
||||||
|
|
||||||
|
cover_mask = "".join(new_cover_mask)
|
||||||
|
|
||||||
|
for i in range(step+1):
|
||||||
|
if print_failed_asserts(i, extrainfo=" (step %d)" % i):
|
||||||
|
found_failed_assert = True
|
||||||
|
|
||||||
|
write_trace(0, step+1, "%d" % coveridx)
|
||||||
|
|
||||||
|
if found_failed_assert:
|
||||||
|
break
|
||||||
|
|
||||||
|
coveridx += 1
|
||||||
|
smt.write("(pop 1)")
|
||||||
|
smt.write("(define-fun covers_%d ((state |%s_s|)) (_ BitVec %d) (bvand (covers_%d state) #b%s))" % (coveridx, topmod, len(cover_desc), coveridx-1, cover_mask))
|
||||||
|
|
||||||
|
if found_failed_assert:
|
||||||
|
break
|
||||||
|
|
||||||
|
if "1" not in cover_mask:
|
||||||
|
retstatus = True
|
||||||
|
break
|
||||||
|
|
||||||
|
step += 1
|
||||||
|
|
||||||
|
if "1" in cover_mask:
|
||||||
|
for i in range(len(cover_mask)):
|
||||||
|
if cover_mask[i] == "1":
|
||||||
|
print_msg("Unreached cover statement at %s." % cover_desc[i])
|
||||||
|
|
||||||
|
else: # not tempind, covermode
|
||||||
step = 0
|
step = 0
|
||||||
retstatus = True
|
retstatus = True
|
||||||
while step < num_steps:
|
while step < num_steps:
|
||||||
|
|
|
@ -42,6 +42,7 @@ class SmtModInfo:
|
||||||
self.wsize = dict()
|
self.wsize = dict()
|
||||||
self.cells = dict()
|
self.cells = dict()
|
||||||
self.asserts = dict()
|
self.asserts = dict()
|
||||||
|
self.covers = dict()
|
||||||
self.anyconsts = dict()
|
self.anyconsts = dict()
|
||||||
|
|
||||||
|
|
||||||
|
@ -331,6 +332,9 @@ class SmtIo:
|
||||||
if fields[1] == "yosys-smt2-assert":
|
if fields[1] == "yosys-smt2-assert":
|
||||||
self.modinfo[self.curmod].asserts[fields[2]] = fields[3]
|
self.modinfo[self.curmod].asserts[fields[2]] = fields[3]
|
||||||
|
|
||||||
|
if fields[1] == "yosys-smt2-cover":
|
||||||
|
self.modinfo[self.curmod].covers[fields[2]] = fields[3]
|
||||||
|
|
||||||
if fields[1] == "yosys-smt2-anyconst":
|
if fields[1] == "yosys-smt2-anyconst":
|
||||||
self.modinfo[self.curmod].anyconsts[fields[2]] = fields[3]
|
self.modinfo[self.curmod].anyconsts[fields[2]] = fields[3]
|
||||||
|
|
||||||
|
@ -567,6 +571,26 @@ class SmtIo:
|
||||||
assert net_path[-1] in self.modinfo[mod].wsize
|
assert net_path[-1] in self.modinfo[mod].wsize
|
||||||
return self.modinfo[mod].wsize[net_path[-1]]
|
return self.modinfo[mod].wsize[net_path[-1]]
|
||||||
|
|
||||||
|
def net_exists(self, mod, net_path):
|
||||||
|
for i in range(len(net_path)-1):
|
||||||
|
if mod not in self.modinfo: return False
|
||||||
|
if net_path[i] not in self.modinfo[mod].cells: return False
|
||||||
|
mod = self.modinfo[mod].cells[net_path[i]]
|
||||||
|
|
||||||
|
if mod not in self.modinfo: return False
|
||||||
|
if net_path[-1] not in self.modinfo[mod].wsize: return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def mem_exists(self, mod, mem_path):
|
||||||
|
for i in range(len(mem_path)-1):
|
||||||
|
if mod not in self.modinfo: return False
|
||||||
|
if mem_path[i] not in self.modinfo[mod].cells: return False
|
||||||
|
mod = self.modinfo[mod].cells[mem_path[i]]
|
||||||
|
|
||||||
|
if mod not in self.modinfo: return False
|
||||||
|
if mem_path[-1] not in self.modinfo[mod].memories: return False
|
||||||
|
return True
|
||||||
|
|
||||||
def mem_expr(self, mod, base, path, portidx=None, infomode=False):
|
def mem_expr(self, mod, base, path, portidx=None, infomode=False):
|
||||||
if len(path) == 1:
|
if len(path) == 1:
|
||||||
assert mod in self.modinfo
|
assert mod in self.modinfo
|
||||||
|
@ -582,8 +606,8 @@ class SmtIo:
|
||||||
nextbase = "(|%s_h %s| %s)" % (mod, path[0], base)
|
nextbase = "(|%s_h %s| %s)" % (mod, path[0], base)
|
||||||
return self.mem_expr(nextmod, nextbase, path[1:], portidx=portidx, infomode=infomode)
|
return self.mem_expr(nextmod, nextbase, path[1:], portidx=portidx, infomode=infomode)
|
||||||
|
|
||||||
def mem_info(self, mod, base, path):
|
def mem_info(self, mod, path):
|
||||||
return self.mem_expr(mod, base, path, infomode=True)
|
return self.mem_expr(mod, "", path, infomode=True)
|
||||||
|
|
||||||
def get_net(self, mod_name, net_path, state_name):
|
def get_net(self, mod_name, net_path, state_name):
|
||||||
return self.get(self.net_expr(mod_name, state_name, net_path))
|
return self.get(self.net_expr(mod_name, state_name, net_path))
|
||||||
|
|
|
@ -84,6 +84,7 @@ std::string AST::type2str(AstNodeType type)
|
||||||
X(AST_PREFIX)
|
X(AST_PREFIX)
|
||||||
X(AST_ASSERT)
|
X(AST_ASSERT)
|
||||||
X(AST_ASSUME)
|
X(AST_ASSUME)
|
||||||
|
X(AST_COVER)
|
||||||
X(AST_FCALL)
|
X(AST_FCALL)
|
||||||
X(AST_TO_BITS)
|
X(AST_TO_BITS)
|
||||||
X(AST_TO_SIGNED)
|
X(AST_TO_SIGNED)
|
||||||
|
|
|
@ -65,6 +65,7 @@ namespace AST
|
||||||
AST_PREFIX,
|
AST_PREFIX,
|
||||||
AST_ASSERT,
|
AST_ASSERT,
|
||||||
AST_ASSUME,
|
AST_ASSUME,
|
||||||
|
AST_COVER,
|
||||||
|
|
||||||
AST_FCALL,
|
AST_FCALL,
|
||||||
AST_TO_BITS,
|
AST_TO_BITS,
|
||||||
|
|
|
@ -1336,9 +1336,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
||||||
// generate $assert cells
|
// generate $assert cells
|
||||||
case AST_ASSERT:
|
case AST_ASSERT:
|
||||||
case AST_ASSUME:
|
case AST_ASSUME:
|
||||||
|
case AST_COVER:
|
||||||
{
|
{
|
||||||
const char *celltype = "$assert";
|
const char *celltype = "$assert";
|
||||||
if (type == AST_ASSUME) celltype = "$assume";
|
if (type == AST_ASSUME) celltype = "$assume";
|
||||||
|
if (type == AST_COVER) celltype = "$cover";
|
||||||
|
|
||||||
log_assert(children.size() == 2);
|
log_assert(children.size() == 2);
|
||||||
|
|
||||||
|
|
|
@ -1400,7 +1400,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
}
|
}
|
||||||
skip_dynamic_range_lvalue_expansion:;
|
skip_dynamic_range_lvalue_expansion:;
|
||||||
|
|
||||||
if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && current_block != NULL)
|
if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_COVER) && current_block != NULL)
|
||||||
{
|
{
|
||||||
std::stringstream sstr;
|
std::stringstream sstr;
|
||||||
sstr << "$formal$" << filename << ":" << linenum << "$" << (autoidx++);
|
sstr << "$formal$" << filename << ":" << linenum << "$" << (autoidx++);
|
||||||
|
@ -1462,7 +1462,7 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
goto apply_newNode;
|
goto apply_newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && children.size() == 1)
|
if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_COVER) && children.size() == 1)
|
||||||
{
|
{
|
||||||
children.push_back(mkconst_int(1, false, 1));
|
children.push_back(mkconst_int(1, false, 1));
|
||||||
did_something = true;
|
did_something = true;
|
||||||
|
|
|
@ -55,7 +55,30 @@ static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean, bool sop_mode)
|
static std::pair<RTLIL::IdString, int> wideports_split(std::string name)
|
||||||
|
{
|
||||||
|
int pos = -1;
|
||||||
|
|
||||||
|
if (name.empty() || name.back() != ']')
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
for (int i = 0; i+1 < GetSize(name); i++) {
|
||||||
|
if (name[i] == '[')
|
||||||
|
pos = i;
|
||||||
|
else if (name[i] < '0' || name[i] > '9')
|
||||||
|
pos = -1;
|
||||||
|
else if (i == pos+1 && name[i] == '0')
|
||||||
|
pos = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos >= 0)
|
||||||
|
return std::pair<RTLIL::IdString, int>("\\" + name.substr(0, pos), atoi(name.c_str() + pos+1)+1);
|
||||||
|
|
||||||
|
failed:
|
||||||
|
return std::pair<RTLIL::IdString, int>("\\" + name, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean, bool sop_mode, bool wideports)
|
||||||
{
|
{
|
||||||
RTLIL::Module *module = nullptr;
|
RTLIL::Module *module = nullptr;
|
||||||
RTLIL::Const *lutptr = NULL;
|
RTLIL::Const *lutptr = NULL;
|
||||||
|
@ -96,6 +119,8 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
||||||
dict<RTLIL::IdString, RTLIL::Const> *obj_attributes = nullptr;
|
dict<RTLIL::IdString, RTLIL::Const> *obj_attributes = nullptr;
|
||||||
dict<RTLIL::IdString, RTLIL::Const> *obj_parameters = nullptr;
|
dict<RTLIL::IdString, RTLIL::Const> *obj_parameters = nullptr;
|
||||||
|
|
||||||
|
dict<RTLIL::IdString, std::pair<int, bool>> wideports_cache;
|
||||||
|
|
||||||
size_t buffer_size = 4096;
|
size_t buffer_size = 4096;
|
||||||
char *buffer = (char*)malloc(buffer_size);
|
char *buffer = (char*)malloc(buffer_size);
|
||||||
int line_count = 0;
|
int line_count = 0;
|
||||||
|
@ -148,7 +173,32 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
||||||
|
|
||||||
if (!strcmp(cmd, ".end"))
|
if (!strcmp(cmd, ".end"))
|
||||||
{
|
{
|
||||||
|
for (auto &wp : wideports_cache)
|
||||||
|
{
|
||||||
|
auto name = wp.first;
|
||||||
|
int width = wp.second.first;
|
||||||
|
bool isinput = wp.second.second;
|
||||||
|
|
||||||
|
RTLIL::Wire *wire = module->addWire(name, width);
|
||||||
|
wire->port_input = isinput;
|
||||||
|
wire->port_output = !isinput;
|
||||||
|
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
|
||||||
|
RTLIL::Wire *other_wire = module->wire(other_name);
|
||||||
|
if (other_wire) {
|
||||||
|
other_wire->port_input = false;
|
||||||
|
other_wire->port_output = false;
|
||||||
|
if (isinput)
|
||||||
|
module->connect(other_wire, SigSpec(wire, i));
|
||||||
|
else
|
||||||
|
module->connect(SigSpec(wire, i), other_wire);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module->fixup_ports();
|
module->fixup_ports();
|
||||||
|
wideports_cache.clear();
|
||||||
|
|
||||||
if (run_clean)
|
if (run_clean)
|
||||||
{
|
{
|
||||||
|
@ -187,9 +237,11 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(cmd, ".inputs") || !strcmp(cmd, ".outputs")) {
|
if (!strcmp(cmd, ".inputs") || !strcmp(cmd, ".outputs"))
|
||||||
|
{
|
||||||
char *p;
|
char *p;
|
||||||
while ((p = strtok(NULL, " \t\r\n")) != NULL) {
|
while ((p = strtok(NULL, " \t\r\n")) != NULL)
|
||||||
|
{
|
||||||
RTLIL::IdString wire_name(stringf("\\%s", p));
|
RTLIL::IdString wire_name(stringf("\\%s", p));
|
||||||
RTLIL::Wire *wire = module->wire(wire_name);
|
RTLIL::Wire *wire = module->wire(wire_name);
|
||||||
if (wire == nullptr)
|
if (wire == nullptr)
|
||||||
|
@ -198,6 +250,14 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
||||||
wire->port_input = true;
|
wire->port_input = true;
|
||||||
else
|
else
|
||||||
wire->port_output = true;
|
wire->port_output = true;
|
||||||
|
|
||||||
|
if (wideports) {
|
||||||
|
std::pair<RTLIL::IdString, int> wp = wideports_split(p);
|
||||||
|
if (wp.second > 0) {
|
||||||
|
wideports_cache[wp.first].first = std::max(wideports_cache[wp.first].first, wp.second);
|
||||||
|
wideports_cache[wp.first].second = !strcmp(cmd, ".inputs");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
obj_attributes = nullptr;
|
obj_attributes = nullptr;
|
||||||
obj_parameters = nullptr;
|
obj_parameters = nullptr;
|
||||||
|
@ -452,6 +512,8 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
log_error("Syntax error in line %d!\n", line_count);
|
log_error("Syntax error in line %d!\n", line_count);
|
||||||
}
|
}
|
||||||
|
@ -469,10 +531,15 @@ struct BlifFrontend : public Frontend {
|
||||||
log(" -sop\n");
|
log(" -sop\n");
|
||||||
log(" Create $sop cells instead of $lut cells\n");
|
log(" Create $sop cells instead of $lut cells\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -wideports\n");
|
||||||
|
log(" Merge ports that match the pattern 'name[int]' into a single\n");
|
||||||
|
log(" multi-bit port 'name'.\n");
|
||||||
|
log("\n");
|
||||||
}
|
}
|
||||||
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
|
||||||
{
|
{
|
||||||
bool sop_mode = false;
|
bool sop_mode = false;
|
||||||
|
bool wideports = false;
|
||||||
|
|
||||||
log_header(design, "Executing BLIF frontend.\n");
|
log_header(design, "Executing BLIF frontend.\n");
|
||||||
|
|
||||||
|
@ -483,11 +550,15 @@ struct BlifFrontend : public Frontend {
|
||||||
sop_mode = true;
|
sop_mode = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (arg == "-wideports") {
|
||||||
|
wideports = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(f, filename, args, argidx);
|
extra_args(f, filename, args, argidx);
|
||||||
|
|
||||||
parse_blif(design, *f, "", true, sop_mode);
|
parse_blif(design, *f, "", true, sop_mode, wideports);
|
||||||
}
|
}
|
||||||
} BlifFrontend;
|
} BlifFrontend;
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,8 @@
|
||||||
|
|
||||||
YOSYS_NAMESPACE_BEGIN
|
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);
|
extern void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name,
|
||||||
|
bool run_clean = false, bool sop_mode = false, bool wideports = false);
|
||||||
|
|
||||||
YOSYS_NAMESPACE_END
|
YOSYS_NAMESPACE_END
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ only have the i386 eval version of Verific:
|
||||||
1.) Use a Makefile.conf like the following one:
|
1.) Use a Makefile.conf like the following one:
|
||||||
|
|
||||||
--snip--
|
--snip--
|
||||||
CONFIG := clang
|
CONFIG := gcc
|
||||||
ENABLE_TCL := 0
|
ENABLE_TCL := 0
|
||||||
ENABLE_PLUGINS := 0
|
ENABLE_PLUGINS := 0
|
||||||
ENABLE_VERIFIC := 1
|
ENABLE_VERIFIC := 1
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -177,8 +177,11 @@ YOSYS_NAMESPACE_END
|
||||||
|
|
||||||
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
|
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
|
||||||
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
|
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
|
||||||
|
"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
|
||||||
"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); }
|
"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); }
|
||||||
"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
|
"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
|
||||||
|
"rand" { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); }
|
||||||
|
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
|
||||||
"logic" { SV_KEYWORD(TOK_REG); }
|
"logic" { SV_KEYWORD(TOK_REG); }
|
||||||
"bit" { SV_KEYWORD(TOK_REG); }
|
"bit" { SV_KEYWORD(TOK_REG); }
|
||||||
|
|
||||||
|
@ -192,14 +195,17 @@ YOSYS_NAMESPACE_END
|
||||||
"genvar" { return TOK_GENVAR; }
|
"genvar" { return TOK_GENVAR; }
|
||||||
"real" { return TOK_REAL; }
|
"real" { return TOK_REAL; }
|
||||||
|
|
||||||
|
"enum" { SV_KEYWORD(TOK_ENUM); }
|
||||||
|
"typedef" { SV_KEYWORD(TOK_TYPEDEF); }
|
||||||
|
|
||||||
[0-9][0-9_]* {
|
[0-9][0-9_]* {
|
||||||
frontend_verilog_yylval.string = new std::string(yytext);
|
frontend_verilog_yylval.string = new std::string(yytext);
|
||||||
return TOK_CONST;
|
return TOK_CONSTVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
|
[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
|
||||||
frontend_verilog_yylval.string = new std::string(yytext);
|
frontend_verilog_yylval.string = new std::string(yytext);
|
||||||
return TOK_CONST;
|
return TOK_CONSTVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
[0-9][0-9_]*\.[0-9][0-9_]*([eE][-+]?[0-9_]+)? {
|
[0-9][0-9_]*\.[0-9][0-9_]*([eE][-+]?[0-9_]+)? {
|
||||||
|
|
|
@ -59,6 +59,7 @@ namespace VERILOG_FRONTEND {
|
||||||
bool default_nettype_wire;
|
bool default_nettype_wire;
|
||||||
bool sv_mode, formal_mode, lib_mode;
|
bool sv_mode, formal_mode, lib_mode;
|
||||||
bool norestrict_mode, assume_asserts_mode;
|
bool norestrict_mode, assume_asserts_mode;
|
||||||
|
bool current_wire_rand, current_wire_const;
|
||||||
std::istream *lexin;
|
std::istream *lexin;
|
||||||
}
|
}
|
||||||
YOSYS_NAMESPACE_END
|
YOSYS_NAMESPACE_END
|
||||||
|
@ -100,7 +101,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
|
||||||
bool boolean;
|
bool boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
%token <string> TOK_STRING TOK_ID TOK_CONST TOK_REALVAL TOK_PRIMITIVE
|
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
|
||||||
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
||||||
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
||||||
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
|
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
|
||||||
|
@ -114,7 +115,8 @@ static void free_attr(std::map<std::string, AstNode*> *al)
|
||||||
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
|
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
|
||||||
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
|
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
|
||||||
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
|
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
|
||||||
%token TOK_RESTRICT TOK_PROPERTY
|
%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
|
||||||
|
%token TOK_RAND TOK_CONST
|
||||||
|
|
||||||
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
|
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
|
||||||
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
|
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
|
||||||
|
@ -355,6 +357,8 @@ delay:
|
||||||
wire_type:
|
wire_type:
|
||||||
{
|
{
|
||||||
astbuf3 = new AstNode(AST_WIRE);
|
astbuf3 = new AstNode(AST_WIRE);
|
||||||
|
current_wire_rand = false;
|
||||||
|
current_wire_const = false;
|
||||||
} wire_type_token_list delay {
|
} wire_type_token_list delay {
|
||||||
$$ = astbuf3;
|
$$ = astbuf3;
|
||||||
};
|
};
|
||||||
|
@ -392,6 +396,12 @@ wire_type_token:
|
||||||
} |
|
} |
|
||||||
TOK_SIGNED {
|
TOK_SIGNED {
|
||||||
astbuf3->is_signed = true;
|
astbuf3->is_signed = true;
|
||||||
|
} |
|
||||||
|
TOK_RAND {
|
||||||
|
current_wire_rand = true;
|
||||||
|
} |
|
||||||
|
TOK_CONST {
|
||||||
|
current_wire_const = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
non_opt_range:
|
non_opt_range:
|
||||||
|
@ -730,7 +740,15 @@ wire_name_list:
|
||||||
wire_name_and_opt_assign | wire_name_list ',' wire_name_and_opt_assign;
|
wire_name_and_opt_assign | wire_name_list ',' wire_name_and_opt_assign;
|
||||||
|
|
||||||
wire_name_and_opt_assign:
|
wire_name_and_opt_assign:
|
||||||
wire_name |
|
wire_name {
|
||||||
|
if (current_wire_rand) {
|
||||||
|
AstNode *wire = new AstNode(AST_IDENTIFIER);
|
||||||
|
AstNode *fcall = new AstNode(AST_FCALL);
|
||||||
|
wire->str = ast_stack.back()->children.back()->str;
|
||||||
|
fcall->str = current_wire_const ? "\\$anyconst" : "\\$anyseq";
|
||||||
|
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, fcall));
|
||||||
|
}
|
||||||
|
} |
|
||||||
wire_name '=' expr {
|
wire_name '=' expr {
|
||||||
AstNode *wire = new AstNode(AST_IDENTIFIER);
|
AstNode *wire = new AstNode(AST_IDENTIFIER);
|
||||||
wire->str = ast_stack.back()->children.back()->str;
|
wire->str = ast_stack.back()->children.back()->str;
|
||||||
|
@ -1000,6 +1018,15 @@ assert:
|
||||||
TOK_ASSUME '(' expr ')' ';' {
|
TOK_ASSUME '(' expr ')' ';' {
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3));
|
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3));
|
||||||
} |
|
} |
|
||||||
|
TOK_COVER '(' expr ')' ';' {
|
||||||
|
ast_stack.back()->children.push_back(new AstNode(AST_COVER, $3));
|
||||||
|
} |
|
||||||
|
TOK_COVER '(' ')' ';' {
|
||||||
|
ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
|
||||||
|
} |
|
||||||
|
TOK_COVER ';' {
|
||||||
|
ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
|
||||||
|
} |
|
||||||
TOK_RESTRICT '(' expr ')' ';' {
|
TOK_RESTRICT '(' expr ')' ';' {
|
||||||
if (norestrict_mode)
|
if (norestrict_mode)
|
||||||
delete $3;
|
delete $3;
|
||||||
|
@ -1014,6 +1041,9 @@ assert_property:
|
||||||
TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
|
TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
|
||||||
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
|
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
|
||||||
} |
|
} |
|
||||||
|
TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
|
||||||
|
ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4));
|
||||||
|
} |
|
||||||
TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
|
TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
|
||||||
if (norestrict_mode)
|
if (norestrict_mode)
|
||||||
delete $4;
|
delete $4;
|
||||||
|
@ -1350,7 +1380,7 @@ basic_expr:
|
||||||
rvalue {
|
rvalue {
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
} |
|
} |
|
||||||
'(' expr ')' TOK_CONST {
|
'(' expr ')' TOK_CONSTVAL {
|
||||||
if ($4->substr(0, 1) != "'")
|
if ($4->substr(0, 1) != "'")
|
||||||
frontend_verilog_yyerror("Syntax error.");
|
frontend_verilog_yyerror("Syntax error.");
|
||||||
AstNode *bits = $2;
|
AstNode *bits = $2;
|
||||||
|
@ -1360,7 +1390,7 @@ basic_expr:
|
||||||
$$ = new AstNode(AST_TO_BITS, bits, val);
|
$$ = new AstNode(AST_TO_BITS, bits, val);
|
||||||
delete $4;
|
delete $4;
|
||||||
} |
|
} |
|
||||||
hierarchical_id TOK_CONST {
|
hierarchical_id TOK_CONSTVAL {
|
||||||
if ($2->substr(0, 1) != "'")
|
if ($2->substr(0, 1) != "'")
|
||||||
frontend_verilog_yyerror("Syntax error.");
|
frontend_verilog_yyerror("Syntax error.");
|
||||||
AstNode *bits = new AstNode(AST_IDENTIFIER);
|
AstNode *bits = new AstNode(AST_IDENTIFIER);
|
||||||
|
@ -1372,14 +1402,14 @@ basic_expr:
|
||||||
delete $1;
|
delete $1;
|
||||||
delete $2;
|
delete $2;
|
||||||
} |
|
} |
|
||||||
TOK_CONST TOK_CONST {
|
TOK_CONSTVAL TOK_CONSTVAL {
|
||||||
$$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
|
$$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
|
||||||
if ($$ == NULL || (*$2)[0] != '\'')
|
if ($$ == NULL || (*$2)[0] != '\'')
|
||||||
log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str());
|
log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str());
|
||||||
delete $1;
|
delete $1;
|
||||||
delete $2;
|
delete $2;
|
||||||
} |
|
} |
|
||||||
TOK_CONST {
|
TOK_CONSTVAL {
|
||||||
$$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
|
$$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
|
||||||
if ($$ == NULL)
|
if ($$ == NULL)
|
||||||
log_error("Value conversion failed: `%s'\n", $1->c_str());
|
log_error("Value conversion failed: `%s'\n", $1->c_str());
|
||||||
|
|
|
@ -116,6 +116,7 @@ struct CellTypes
|
||||||
|
|
||||||
setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
|
setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||||
setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
|
setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||||
|
setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
|
||||||
setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
|
setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
|
||||||
setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
|
setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
|
||||||
setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
|
setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
|
||||||
|
|
|
@ -1026,7 +1026,7 @@ namespace {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cell->type.in("$assert", "$assume")) {
|
if (cell->type.in("$assert", "$assume", "$cover")) {
|
||||||
port("\\A", 1);
|
port("\\A", 1);
|
||||||
port("\\EN", 1);
|
port("\\EN", 1);
|
||||||
check_expected();
|
check_expected();
|
||||||
|
@ -1819,6 +1819,14 @@ RTLIL::Cell* RTLIL::Module::addAssume(RTLIL::IdString name, RTLIL::SigSpec sig_a
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RTLIL::Cell* RTLIL::Module::addCover(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en)
|
||||||
|
{
|
||||||
|
RTLIL::Cell *cell = addCell(name, "$cover");
|
||||||
|
cell->setPort("\\A", sig_a);
|
||||||
|
cell->setPort("\\EN", sig_en);
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
RTLIL::Cell* RTLIL::Module::addEquiv(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y)
|
RTLIL::Cell* RTLIL::Module::addEquiv(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y)
|
||||||
{
|
{
|
||||||
RTLIL::Cell *cell = addCell(name, "$equiv");
|
RTLIL::Cell *cell = addCell(name, "$equiv");
|
||||||
|
@ -2050,6 +2058,7 @@ RTLIL::Memory::Memory()
|
||||||
hashidx_ = hashidx_count;
|
hashidx_ = hashidx_count;
|
||||||
|
|
||||||
width = 1;
|
width = 1;
|
||||||
|
start_offset = 0;
|
||||||
size = 0;
|
size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1007,6 +1007,7 @@ public:
|
||||||
RTLIL::Cell* addTribuf (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y);
|
RTLIL::Cell* addTribuf (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y);
|
||||||
RTLIL::Cell* addAssert (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en);
|
RTLIL::Cell* addAssert (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en);
|
||||||
RTLIL::Cell* addAssume (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en);
|
RTLIL::Cell* addAssume (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en);
|
||||||
|
RTLIL::Cell* addCover (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en);
|
||||||
RTLIL::Cell* addEquiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y);
|
RTLIL::Cell* addEquiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y);
|
||||||
|
|
||||||
RTLIL::Cell* addSr (RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity = true, bool clr_polarity = true);
|
RTLIL::Cell* addSr (RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity = true, bool clr_polarity = true);
|
||||||
|
|
|
@ -507,11 +507,7 @@ struct SatGen
|
||||||
std::vector<int> undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep);
|
std::vector<int> undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep);
|
||||||
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
|
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
|
||||||
|
|
||||||
int maybe_one_hot = ez->CONST_FALSE;
|
int maybe_a = ez->CONST_TRUE;
|
||||||
int maybe_many_hot = ez->CONST_FALSE;
|
|
||||||
|
|
||||||
int sure_one_hot = ez->CONST_FALSE;
|
|
||||||
int sure_many_hot = ez->CONST_FALSE;
|
|
||||||
|
|
||||||
std::vector<int> bits_set = std::vector<int>(undef_y.size(), ez->CONST_FALSE);
|
std::vector<int> bits_set = std::vector<int>(undef_y.size(), ez->CONST_FALSE);
|
||||||
std::vector<int> bits_clr = std::vector<int>(undef_y.size(), ez->CONST_FALSE);
|
std::vector<int> bits_clr = std::vector<int>(undef_y.size(), ez->CONST_FALSE);
|
||||||
|
@ -524,18 +520,12 @@ struct SatGen
|
||||||
int maybe_s = ez->OR(s.at(i), undef_s.at(i));
|
int maybe_s = ez->OR(s.at(i), undef_s.at(i));
|
||||||
int sure_s = ez->AND(s.at(i), ez->NOT(undef_s.at(i)));
|
int sure_s = ez->AND(s.at(i), ez->NOT(undef_s.at(i)));
|
||||||
|
|
||||||
maybe_one_hot = ez->OR(maybe_one_hot, maybe_s);
|
maybe_a = ez->AND(maybe_a, ez->NOT(sure_s));
|
||||||
maybe_many_hot = ez->OR(maybe_many_hot, ez->AND(maybe_one_hot, maybe_s));
|
|
||||||
|
|
||||||
sure_one_hot = ez->OR(sure_one_hot, sure_s);
|
bits_set = ez->vec_ite(maybe_s, ez->vec_or(bits_set, ez->vec_or(part_of_b, part_of_undef_b)), bits_set);
|
||||||
sure_many_hot = ez->OR(sure_many_hot, ez->AND(sure_one_hot, sure_s));
|
bits_clr = ez->vec_ite(maybe_s, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(part_of_b), part_of_undef_b)), bits_clr);
|
||||||
|
|
||||||
bits_set = ez->vec_ite(maybe_s, ez->vec_or(bits_set, ez->vec_or(bits_set, ez->vec_or(part_of_b, part_of_undef_b))), bits_set);
|
|
||||||
bits_clr = ez->vec_ite(maybe_s, ez->vec_or(bits_clr, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(part_of_b), part_of_undef_b))), bits_clr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int maybe_a = ez->NOT(maybe_one_hot);
|
|
||||||
|
|
||||||
bits_set = ez->vec_ite(maybe_a, ez->vec_or(bits_set, ez->vec_or(bits_set, ez->vec_or(a, undef_a))), bits_set);
|
bits_set = ez->vec_ite(maybe_a, ez->vec_or(bits_set, ez->vec_or(bits_set, ez->vec_or(a, undef_a))), bits_set);
|
||||||
bits_clr = ez->vec_ite(maybe_a, ez->vec_or(bits_clr, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(a), undef_a))), bits_clr);
|
bits_clr = ez->vec_ite(maybe_a, ez->vec_or(bits_clr, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(a), undef_a))), bits_clr);
|
||||||
|
|
||||||
|
|
|
@ -421,7 +421,7 @@ pass. The combinatorial logic cells can be mapped to physical cells from a Liber
|
||||||
using the {\tt abc} pass.
|
using the {\tt abc} pass.
|
||||||
|
|
||||||
\begin{fixme}
|
\begin{fixme}
|
||||||
Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$equiv}, {\tt \$initstate}, {\tt \$anyconst}, and {\tt \$anyseq} cells.
|
Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$cover}, {\tt \$equiv}, {\tt \$initstate}, {\tt \$anyconst}, and {\tt \$anyseq} cells.
|
||||||
\end{fixme}
|
\end{fixme}
|
||||||
|
|
||||||
\begin{fixme}
|
\begin{fixme}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
for f in $( find . -name .gitignore ); do sed -re "s,^,find ${f%.gitignore} -name ',; s,$,' | xargs rm -f,;" $f; done | bash -v
|
for f in $( find . -name .gitignore ); do sed -Ee "s,^,find ${f%.gitignore} -name ',; s,$,' | xargs rm -f,;" $f; done | bash -v
|
||||||
|
|
|
@ -59,7 +59,7 @@ struct EquivSimpleWorker
|
||||||
for (auto &conn : cell->connections())
|
for (auto &conn : cell->connections())
|
||||||
if (yosys_celltypes.cell_input(cell->type, conn.first))
|
if (yosys_celltypes.cell_input(cell->type, conn.first))
|
||||||
for (auto bit : sigmap(conn.second)) {
|
for (auto bit : sigmap(conn.second)) {
|
||||||
if (cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_")) {
|
if (cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_", "$ff", "$_FF_")) {
|
||||||
if (!conn.first.in("\\CLK", "\\C"))
|
if (!conn.first.in("\\CLK", "\\C"))
|
||||||
next_seed.insert(bit);
|
next_seed.insert(bit);
|
||||||
} else
|
} else
|
||||||
|
@ -329,7 +329,7 @@ struct EquivSimplePass : public Pass {
|
||||||
unproven_cells_counter, GetSize(unproven_equiv_cells), log_id(module));
|
unproven_cells_counter, GetSize(unproven_equiv_cells), log_id(module));
|
||||||
|
|
||||||
for (auto cell : module->cells()) {
|
for (auto cell : module->cells()) {
|
||||||
if (!ct.cell_known(cell->type) && !cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_"))
|
if (!ct.cell_known(cell->type) && !cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_", "$ff", "$_FF_"))
|
||||||
continue;
|
continue;
|
||||||
for (auto &conn : cell->connections())
|
for (auto &conn : cell->connections())
|
||||||
if (yosys_celltypes.cell_output(cell->type, conn.first))
|
if (yosys_celltypes.cell_output(cell->type, conn.first))
|
||||||
|
|
|
@ -54,13 +54,27 @@ struct FsmExpand
|
||||||
if (cell->getPort("\\A").size() < 2)
|
if (cell->getPort("\\A").size() < 2)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
int in_bits = 0;
|
||||||
RTLIL::SigSpec new_signals;
|
RTLIL::SigSpec new_signals;
|
||||||
if (cell->hasPort("\\A"))
|
|
||||||
|
if (cell->hasPort("\\A")) {
|
||||||
|
in_bits += GetSize(cell->getPort("\\A"));
|
||||||
new_signals.append(assign_map(cell->getPort("\\A")));
|
new_signals.append(assign_map(cell->getPort("\\A")));
|
||||||
if (cell->hasPort("\\B"))
|
}
|
||||||
|
|
||||||
|
if (cell->hasPort("\\B")) {
|
||||||
|
in_bits += GetSize(cell->getPort("\\B"));
|
||||||
new_signals.append(assign_map(cell->getPort("\\B")));
|
new_signals.append(assign_map(cell->getPort("\\B")));
|
||||||
if (cell->hasPort("\\S"))
|
}
|
||||||
|
|
||||||
|
if (cell->hasPort("\\S")) {
|
||||||
|
in_bits += GetSize(cell->getPort("\\S"));
|
||||||
new_signals.append(assign_map(cell->getPort("\\S")));
|
new_signals.append(assign_map(cell->getPort("\\S")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_bits > 8)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (cell->hasPort("\\Y"))
|
if (cell->hasPort("\\Y"))
|
||||||
new_signals.append(assign_map(cell->getPort("\\Y")));
|
new_signals.append(assign_map(cell->getPort("\\Y")));
|
||||||
|
|
||||||
|
@ -173,6 +187,16 @@ struct FsmExpand
|
||||||
new_ctrl_out.append(output_sig);
|
new_ctrl_out.append(output_sig);
|
||||||
fsm_cell->setPort("\\CTRL_OUT", new_ctrl_out);
|
fsm_cell->setPort("\\CTRL_OUT", new_ctrl_out);
|
||||||
|
|
||||||
|
if (GetSize(input_sig) > 10)
|
||||||
|
log_warning("Cell %s.%s (%s) has %d input bits, merging into FSM %s.%s might be problematic.\n",
|
||||||
|
log_id(cell->module), log_id(cell), log_id(cell->type),
|
||||||
|
GetSize(input_sig), log_id(fsm_cell->module), log_id(fsm_cell));
|
||||||
|
|
||||||
|
if (GetSize(fsm_data.transition_table) > 10000)
|
||||||
|
log_warning("Transition table for FSM %s.%s already has %d rows, merging more cells "
|
||||||
|
"into this FSM might be problematic.\n", log_id(fsm_cell->module), log_id(fsm_cell),
|
||||||
|
GetSize(fsm_data.transition_table));
|
||||||
|
|
||||||
std::vector<FsmData::transition_t> new_transition_table;
|
std::vector<FsmData::transition_t> new_transition_table;
|
||||||
for (auto &tr : fsm_data.transition_table) {
|
for (auto &tr : fsm_data.transition_table) {
|
||||||
for (int i = 0; i < (1 << input_sig.size()); i++) {
|
for (int i = 0; i < (1 << input_sig.size()); i++) {
|
||||||
|
|
|
@ -175,16 +175,12 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
|
||||||
{
|
{
|
||||||
filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".v";
|
filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".v";
|
||||||
if (check_file_exists(filename)) {
|
if (check_file_exists(filename)) {
|
||||||
std::vector<std::string> args;
|
|
||||||
args.push_back(filename);
|
|
||||||
Frontend::frontend_call(design, NULL, filename, "verilog");
|
Frontend::frontend_call(design, NULL, filename, "verilog");
|
||||||
goto loaded_module;
|
goto loaded_module;
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".il";
|
filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".il";
|
||||||
if (check_file_exists(filename)) {
|
if (check_file_exists(filename)) {
|
||||||
std::vector<std::string> args;
|
|
||||||
args.push_back(filename);
|
|
||||||
Frontend::frontend_call(design, NULL, filename, "ilang");
|
Frontend::frontend_call(design, NULL, filename, "ilang");
|
||||||
goto loaded_module;
|
goto loaded_module;
|
||||||
}
|
}
|
||||||
|
@ -317,7 +313,7 @@ bool set_keep_assert(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod)
|
||||||
if (cache.count(mod) == 0)
|
if (cache.count(mod) == 0)
|
||||||
for (auto c : mod->cells()) {
|
for (auto c : mod->cells()) {
|
||||||
RTLIL::Module *m = mod->design->module(c->type);
|
RTLIL::Module *m = mod->design->module(c->type);
|
||||||
if ((m != nullptr && set_keep_assert(cache, m)) || c->type.in("$assert", "$assume"))
|
if ((m != nullptr && set_keep_assert(cache, m)) || c->type.in("$assert", "$assume", "$cover"))
|
||||||
return cache[mod] = true;
|
return cache[mod] = true;
|
||||||
}
|
}
|
||||||
return cache[mod];
|
return cache[mod];
|
||||||
|
|
|
@ -64,7 +64,7 @@ struct keep_cache_t
|
||||||
|
|
||||||
bool query(Cell *cell)
|
bool query(Cell *cell)
|
||||||
{
|
{
|
||||||
if (cell->type.in("$memwr", "$meminit", "$assert", "$assume"))
|
if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$cover"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (cell->has_keep_attr())
|
if (cell->has_keep_attr())
|
||||||
|
|
|
@ -259,6 +259,29 @@ bool is_one_or_minus_one(const Const &value, bool is_signed, bool &is_negative)
|
||||||
return last_bit_one;
|
return last_bit_one;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the signal has only one bit set, return the index of that bit.
|
||||||
|
// otherwise return -1
|
||||||
|
int get_onehot_bit_index(RTLIL::SigSpec signal)
|
||||||
|
{
|
||||||
|
int bit_index = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < GetSize(signal); i++)
|
||||||
|
{
|
||||||
|
if (signal[i] == RTLIL::State::S0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (signal[i] != RTLIL::State::S1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (bit_index != -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
bit_index = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bit_index;
|
||||||
|
}
|
||||||
|
|
||||||
void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool clkinv)
|
void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool clkinv)
|
||||||
{
|
{
|
||||||
if (!design->selected(module))
|
if (!design->selected(module))
|
||||||
|
@ -1167,6 +1190,103 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// replace a<0 or a>=0 with the top bit of a
|
||||||
|
if (do_fine && (cell->type == "$lt" || cell->type == "$ge" || cell->type == "$gt" || cell->type == "$le"))
|
||||||
|
{
|
||||||
|
//used to decide whether the signal needs to be negated
|
||||||
|
bool is_lt = false;
|
||||||
|
|
||||||
|
//references the variable signal in the comparison
|
||||||
|
RTLIL::SigSpec sigVar;
|
||||||
|
|
||||||
|
//references the constant signal in the comparison
|
||||||
|
RTLIL::SigSpec sigConst;
|
||||||
|
|
||||||
|
// note that this signal must be constant for the optimization
|
||||||
|
// to take place, but it is not checked beforehand.
|
||||||
|
// If new passes are added, this signal must be checked for const-ness
|
||||||
|
|
||||||
|
//width of the variable port
|
||||||
|
int width;
|
||||||
|
|
||||||
|
bool var_signed;
|
||||||
|
|
||||||
|
if (cell->type == "$lt" || cell->type == "$ge") {
|
||||||
|
is_lt = cell->type == "$lt" ? 1 : 0;
|
||||||
|
sigVar = cell->getPort("\\A");
|
||||||
|
sigConst = cell->getPort("\\B");
|
||||||
|
width = cell->parameters["\\A_WIDTH"].as_int();
|
||||||
|
var_signed = cell->parameters["\\A_SIGNED"].as_bool();
|
||||||
|
} else
|
||||||
|
if (cell->type == "$gt" || cell->type == "$le") {
|
||||||
|
is_lt = cell->type == "$gt" ? 1 : 0;
|
||||||
|
sigVar = cell->getPort("\\B");
|
||||||
|
sigConst = cell->getPort("\\A");
|
||||||
|
width = cell->parameters["\\B_WIDTH"].as_int();
|
||||||
|
var_signed = cell->parameters["\\B_SIGNED"].as_bool();
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace a(signed) < 0 with the high bit of a
|
||||||
|
if (sigConst.is_fully_const() && sigConst.is_fully_zero() && var_signed == true)
|
||||||
|
{
|
||||||
|
RTLIL::SigSpec a_prime(RTLIL::State::S0, cell->parameters["\\Y_WIDTH"].as_int());
|
||||||
|
a_prime[0] = sigVar[width - 1];
|
||||||
|
if (is_lt) {
|
||||||
|
log("Replacing %s cell `%s' (implementing X<0) with X[%d]: %s\n",
|
||||||
|
log_id(cell->type), log_id(cell), width-1, log_signal(a_prime));
|
||||||
|
module->connect(cell->getPort("\\Y"), a_prime);
|
||||||
|
module->remove(cell);
|
||||||
|
} else {
|
||||||
|
log("Replacing %s cell `%s' (implementing X>=0) with ~X[%d]: %s\n",
|
||||||
|
log_id(cell->type), log_id(cell), width-1, log_signal(a_prime));
|
||||||
|
module->addNot(NEW_ID, a_prime, cell->getPort("\\Y"));
|
||||||
|
module->remove(cell);
|
||||||
|
}
|
||||||
|
did_something = true;
|
||||||
|
goto next_cell;
|
||||||
|
} else
|
||||||
|
if (sigConst.is_fully_const() && sigConst.is_fully_def() && var_signed == false)
|
||||||
|
{
|
||||||
|
if (sigConst.is_fully_zero()) {
|
||||||
|
RTLIL::SigSpec a_prime(RTLIL::State::S0, 1);
|
||||||
|
if (is_lt) {
|
||||||
|
log("Replacing %s cell `%s' (implementing unsigned X<0) with constant false.\n",
|
||||||
|
log_id(cell->type), log_id(cell));
|
||||||
|
a_prime[0] = RTLIL::State::S0;
|
||||||
|
} else {
|
||||||
|
log("Replacing %s cell `%s' (implementing unsigned X>=0) with constant true.\n",
|
||||||
|
log_id(cell->type), log_id(cell));
|
||||||
|
a_prime[0] = RTLIL::State::S1;
|
||||||
|
}
|
||||||
|
module->connect(cell->getPort("\\Y"), a_prime);
|
||||||
|
module->remove(cell);
|
||||||
|
did_something = true;
|
||||||
|
goto next_cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
int const_bit_set = get_onehot_bit_index(sigConst);
|
||||||
|
if (const_bit_set >= 0) {
|
||||||
|
int bit_set = const_bit_set;
|
||||||
|
RTLIL::SigSpec a_prime(RTLIL::State::S0, width - bit_set);
|
||||||
|
for (int i = bit_set; i < width; i++) {
|
||||||
|
a_prime[i - bit_set] = sigVar[i];
|
||||||
|
}
|
||||||
|
if (is_lt) {
|
||||||
|
log("Replacing %s cell `%s' (implementing unsigned X<%s) with !X[%d:%d]: %s.\n",
|
||||||
|
log_id(cell->type), log_id(cell), log_signal(sigConst), width - 1, bit_set, log_signal(a_prime));
|
||||||
|
module->addLogicNot(NEW_ID, a_prime, cell->getPort("\\Y"));
|
||||||
|
} else {
|
||||||
|
log("Replacing %s cell `%s' (implementing unsigned X>=%s) with |X[%d:%d]: %s.\n",
|
||||||
|
log_id(cell->type), log_id(cell), log_signal(sigConst), width - 1, bit_set, log_signal(a_prime));
|
||||||
|
module->addReduceOr(NEW_ID, a_prime, cell->getPort("\\Y"));
|
||||||
|
}
|
||||||
|
module->remove(cell);
|
||||||
|
did_something = true;
|
||||||
|
goto next_cell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
next_cell:;
|
next_cell:;
|
||||||
#undef ACTION_DO
|
#undef ACTION_DO
|
||||||
#undef ACTION_DO_Y
|
#undef ACTION_DO_Y
|
||||||
|
|
|
@ -41,9 +41,27 @@ void remove_init_attr(SigSpec sig)
|
||||||
|
|
||||||
bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
|
bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
|
||||||
{
|
{
|
||||||
SigSpec sig_e = dlatch->getPort("\\EN");
|
SigSpec sig_e;
|
||||||
|
State on_state, off_state;
|
||||||
|
|
||||||
if (sig_e == State::S0)
|
if (dlatch->type == "$dlatch") {
|
||||||
|
sig_e = assign_map(dlatch->getPort("\\EN"));
|
||||||
|
on_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S1 : State::S0;
|
||||||
|
off_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S0 : State::S1;
|
||||||
|
} else
|
||||||
|
if (dlatch->type == "$_DLATCH_P_") {
|
||||||
|
sig_e = assign_map(dlatch->getPort("\\E"));
|
||||||
|
on_state = State::S1;
|
||||||
|
off_state = State::S0;
|
||||||
|
} else
|
||||||
|
if (dlatch->type == "$_DLATCH_N_") {
|
||||||
|
sig_e = assign_map(dlatch->getPort("\\E"));
|
||||||
|
on_state = State::S0;
|
||||||
|
off_state = State::S1;
|
||||||
|
} else
|
||||||
|
log_abort();
|
||||||
|
|
||||||
|
if (sig_e == off_state)
|
||||||
{
|
{
|
||||||
RTLIL::Const val_init;
|
RTLIL::Const val_init;
|
||||||
for (auto bit : dff_init_map(dlatch->getPort("\\Q")))
|
for (auto bit : dff_init_map(dlatch->getPort("\\Q")))
|
||||||
|
@ -52,7 +70,7 @@ bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
|
||||||
goto delete_dlatch;
|
goto delete_dlatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sig_e == State::S1)
|
if (sig_e == on_state)
|
||||||
{
|
{
|
||||||
mod->connect(dlatch->getPort("\\Q"), dlatch->getPort("\\D"));
|
mod->connect(dlatch->getPort("\\Q"), dlatch->getPort("\\D"));
|
||||||
goto delete_dlatch;
|
goto delete_dlatch;
|
||||||
|
@ -268,7 +286,7 @@ struct OptRmdffPass : public Pass {
|
||||||
"$ff", "$dff", "$adff"))
|
"$ff", "$dff", "$adff"))
|
||||||
dff_list.push_back(cell->name);
|
dff_list.push_back(cell->name);
|
||||||
|
|
||||||
if (cell->type == "$dlatch")
|
if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_"))
|
||||||
dlatch_list.push_back(cell->name);
|
dlatch_list.push_back(cell->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,11 @@
|
||||||
// Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025
|
// Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025
|
||||||
// http://en.wikipedia.org/wiki/Topological_sorting
|
// http://en.wikipedia.org/wiki/Topological_sorting
|
||||||
|
|
||||||
#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; dch -f; map {D}"
|
#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
|
||||||
#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; dch -f; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
|
#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p"
|
||||||
#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2"
|
#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2"
|
||||||
#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}"
|
#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}"
|
||||||
#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; dch -f; map"
|
#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
|
||||||
|
|
||||||
#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}"
|
#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}"
|
||||||
#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
|
#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
|
||||||
|
|
|
@ -1305,6 +1305,14 @@ endmodule
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
|
|
||||||
|
module \$cover (A, EN);
|
||||||
|
|
||||||
|
input A, EN;
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// --------------------------------------------------------
|
||||||
|
|
||||||
module \$initstate (Y);
|
module \$initstate (Y);
|
||||||
|
|
||||||
output reg Y = 1;
|
output reg Y = 1;
|
||||||
|
|
Loading…
Reference in New Issue