mirror of
https://github.com/YosysHQ/sby.git
synced 2025-04-06 14:24:08 +00:00
Merge pull request #210 from jix/witness_flow
Updated formal flow with new witness format
This commit is contained in:
commit
9a14f4d238
|
@ -153,6 +153,12 @@ options are:
|
||||||
| ``tbtop`` | All | The top module for generated Verilog test benches, as |
|
| ``tbtop`` | All | The top module for generated Verilog test benches, as |
|
||||||
| | | hierarchical path relative to the design top module. |
|
| | | hierarchical path relative to the design top module. |
|
||||||
+------------------+------------+---------------------------------------------------------+
|
+------------------+------------+---------------------------------------------------------+
|
||||||
|
| ``make_model`` | All | Force generation of the named formal models. Takes a |
|
||||||
|
| | | comma-separated list of model names. For a model |
|
||||||
|
| | | ``<name>`` this will generate the |
|
||||||
|
| | | ``model/design_<name>.*`` files within the working |
|
||||||
|
| | | directory, even when not required to run the task. |
|
||||||
|
+------------------+------------+---------------------------------------------------------+
|
||||||
| ``smtc`` | ``bmc``, | Pass this ``.smtc`` file to the smtbmc engine. All |
|
| ``smtc`` | ``bmc``, | Pass this ``.smtc`` file to the smtbmc engine. All |
|
||||||
| | ``prove``, | other engines are disabled when this option is used. |
|
| | ``prove``, | other engines are disabled when this option is used. |
|
||||||
| | ``cover`` | Default: None |
|
| | ``cover`` | Default: None |
|
||||||
|
@ -340,6 +346,15 @@ solvers:
|
||||||
Solver options are passed as additional arguments to the ABC command
|
Solver options are passed as additional arguments to the ABC command
|
||||||
implementing the solver.
|
implementing the solver.
|
||||||
|
|
||||||
|
|
||||||
|
``none`` engine
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The ``none`` engine does not run any solver. It can be used together with the
|
||||||
|
``make_model`` option to manually generate any model supported by one of the
|
||||||
|
other engines. This makes it easier to use the same models outside of sby.
|
||||||
|
|
||||||
|
|
||||||
Script section
|
Script section
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|
|
@ -391,7 +391,7 @@ class SbyAutotune:
|
||||||
else:
|
else:
|
||||||
self.task.copy_src()
|
self.task.copy_src()
|
||||||
|
|
||||||
self.model(None, "base")
|
self.model(None, "prep")
|
||||||
self.task.taskloop.run()
|
self.task.taskloop.run()
|
||||||
|
|
||||||
if self.task.status == "ERROR":
|
if self.task.status == "ERROR":
|
||||||
|
|
|
@ -81,6 +81,7 @@ class SbyProc:
|
||||||
self.linebuffer = ""
|
self.linebuffer = ""
|
||||||
self.logstderr = logstderr
|
self.logstderr = logstderr
|
||||||
self.silent = silent
|
self.silent = silent
|
||||||
|
self.wait = False
|
||||||
|
|
||||||
self.task.update_proc_pending(self)
|
self.task.update_proc_pending(self)
|
||||||
|
|
||||||
|
@ -130,7 +131,7 @@ class SbyProc:
|
||||||
self.error_callback(retcode)
|
self.error_callback(retcode)
|
||||||
|
|
||||||
def terminate(self, timeout=False):
|
def terminate(self, timeout=False):
|
||||||
if self.task.opt_wait and not timeout:
|
if (self.task.opt_wait or self.wait) and not timeout:
|
||||||
return
|
return
|
||||||
if self.running:
|
if self.running:
|
||||||
if not self.silent:
|
if not self.silent:
|
||||||
|
@ -585,25 +586,43 @@ class SbyTask(SbyConfig):
|
||||||
if not os.path.isdir(f"{self.workdir}/model"):
|
if not os.path.isdir(f"{self.workdir}/model"):
|
||||||
os.makedirs(f"{self.workdir}/model")
|
os.makedirs(f"{self.workdir}/model")
|
||||||
|
|
||||||
def print_common_prep(check):
|
if model_name == "prep":
|
||||||
print("scc -select; simplemap; select -clear", file=f)
|
with open(f"""{self.workdir}/model/design_prep.ys""", "w") as f:
|
||||||
if self.opt_multiclock:
|
print(f"# running in {self.workdir}/model/", file=f)
|
||||||
print("clk2fflogic", file=f)
|
print(f"""read_ilang design.il""", file=f)
|
||||||
else:
|
print("scc -select; simplemap; select -clear", file=f)
|
||||||
print("async2sync", file=f)
|
print("memory_nordff", file=f)
|
||||||
print("chformal -assume -early", file=f)
|
if self.opt_multiclock:
|
||||||
if self.opt_mode in ["bmc", "prove"]:
|
print("clk2fflogic", file=f)
|
||||||
print("chformal -live -fair -cover -remove", file=f)
|
else:
|
||||||
if self.opt_mode == "cover":
|
print("async2sync", file=f)
|
||||||
print("chformal -live -fair -remove", file=f)
|
print("chformal -assume -early", file=f)
|
||||||
if self.opt_mode == "live":
|
print("opt_clean", file=f)
|
||||||
print("chformal -assert2assume", file=f)
|
print("formalff -setundef -clk2ff -ff2anyinit", file=f)
|
||||||
print("chformal -cover -remove", file=f)
|
if self.opt_mode in ["bmc", "prove"]:
|
||||||
print("opt_clean", file=f)
|
print("chformal -live -fair -cover -remove", file=f)
|
||||||
print("setundef -anyseq", file=f)
|
if self.opt_mode == "cover":
|
||||||
print("opt -keepdc -fast", file=f)
|
print("chformal -live -fair -remove", file=f)
|
||||||
print("check", file=f)
|
if self.opt_mode == "live":
|
||||||
print(f"hierarchy {check}", file=f)
|
print("chformal -assert2assume", file=f)
|
||||||
|
print("chformal -cover -remove", file=f)
|
||||||
|
print("opt_clean", file=f)
|
||||||
|
print("check", file=f) # can't detect undriven wires past this point
|
||||||
|
print("setundef -undriven -anyseq", file=f)
|
||||||
|
print("opt -fast", file=f)
|
||||||
|
print("rename -witness", file=f)
|
||||||
|
print("opt_clean", file=f)
|
||||||
|
print(f"""write_rtlil ../model/design_prep.il""", file=f)
|
||||||
|
|
||||||
|
proc = SbyProc(
|
||||||
|
self,
|
||||||
|
model_name,
|
||||||
|
self.model("base"),
|
||||||
|
"cd {}/model; {} -ql design_{s}.log design_{s}.ys".format(self.workdir, self.exe_paths["yosys"], s=model_name)
|
||||||
|
)
|
||||||
|
proc.checkretcode = True
|
||||||
|
|
||||||
|
return [proc]
|
||||||
|
|
||||||
if model_name == "base":
|
if model_name == "base":
|
||||||
with open(f"""{self.workdir}/model/design.ys""", "w") as f:
|
with open(f"""{self.workdir}/model/design.ys""", "w") as f:
|
||||||
|
@ -639,12 +658,11 @@ class SbyTask(SbyConfig):
|
||||||
if re.match(r"^smt2(_syn)?(_nomem)?(_stbv|_stdt)?$", model_name):
|
if re.match(r"^smt2(_syn)?(_nomem)?(_stbv|_stdt)?$", model_name):
|
||||||
with open(f"{self.workdir}/model/design_{model_name}.ys", "w") as f:
|
with open(f"{self.workdir}/model/design_{model_name}.ys", "w") as f:
|
||||||
print(f"# running in {self.workdir}/model/", file=f)
|
print(f"# running in {self.workdir}/model/", file=f)
|
||||||
print(f"""read_ilang design.il""", file=f)
|
print(f"""read_ilang design_prep.il""", file=f)
|
||||||
|
print("hierarchy -smtcheck", file=f)
|
||||||
if "_nomem" in model_name:
|
if "_nomem" in model_name:
|
||||||
print("memory_map", file=f)
|
print("memory_map -formal", file=f)
|
||||||
else:
|
print("formalff -setundef -clk2ff -ff2anyinit", file=f)
|
||||||
print("memory_nordff", file=f)
|
|
||||||
print_common_prep("-smtcheck")
|
|
||||||
if "_syn" in model_name:
|
if "_syn" in model_name:
|
||||||
print("techmap", file=f)
|
print("techmap", file=f)
|
||||||
print("opt -fast", file=f)
|
print("opt -fast", file=f)
|
||||||
|
@ -662,7 +680,7 @@ class SbyTask(SbyConfig):
|
||||||
proc = SbyProc(
|
proc = SbyProc(
|
||||||
self,
|
self,
|
||||||
model_name,
|
model_name,
|
||||||
self.model("base"),
|
self.model("prep"),
|
||||||
"cd {}/model; {} -ql design_{s}.log design_{s}.ys".format(self.workdir, self.exe_paths["yosys"], s=model_name)
|
"cd {}/model; {} -ql design_{s}.log design_{s}.ys".format(self.workdir, self.exe_paths["yosys"], s=model_name)
|
||||||
)
|
)
|
||||||
proc.checkretcode = True
|
proc.checkretcode = True
|
||||||
|
@ -672,12 +690,11 @@ class SbyTask(SbyConfig):
|
||||||
if re.match(r"^btor(_syn)?(_nomem)?$", model_name):
|
if re.match(r"^btor(_syn)?(_nomem)?$", model_name):
|
||||||
with open(f"{self.workdir}/model/design_{model_name}.ys", "w") as f:
|
with open(f"{self.workdir}/model/design_{model_name}.ys", "w") as f:
|
||||||
print(f"# running in {self.workdir}/model/", file=f)
|
print(f"# running in {self.workdir}/model/", file=f)
|
||||||
print(f"""read_ilang design.il""", file=f)
|
print(f"""read_ilang design_prep.il""", file=f)
|
||||||
|
print("hierarchy -simcheck", file=f)
|
||||||
if "_nomem" in model_name:
|
if "_nomem" in model_name:
|
||||||
print("memory_map", file=f)
|
print("memory_map -formal", file=f)
|
||||||
else:
|
print("formalff -setundef -clk2ff -ff2anyinit", file=f)
|
||||||
print("memory_nordff", file=f)
|
|
||||||
print_common_prep("-simcheck")
|
|
||||||
print("flatten", file=f)
|
print("flatten", file=f)
|
||||||
print("setundef -undriven -anyseq", file=f)
|
print("setundef -undriven -anyseq", file=f)
|
||||||
if "_syn" in model_name:
|
if "_syn" in model_name:
|
||||||
|
@ -687,7 +704,7 @@ class SbyTask(SbyConfig):
|
||||||
print("abc", file=f)
|
print("abc", file=f)
|
||||||
print("opt_clean", file=f)
|
print("opt_clean", file=f)
|
||||||
else:
|
else:
|
||||||
print("opt -fast -keepdc", file=f)
|
print("opt -fast", file=f)
|
||||||
print("delete -output", file=f)
|
print("delete -output", file=f)
|
||||||
print("dffunmap", file=f)
|
print("dffunmap", file=f)
|
||||||
print("stat", file=f)
|
print("stat", file=f)
|
||||||
|
@ -697,7 +714,7 @@ class SbyTask(SbyConfig):
|
||||||
proc = SbyProc(
|
proc = SbyProc(
|
||||||
self,
|
self,
|
||||||
model_name,
|
model_name,
|
||||||
self.model("base"),
|
self.model("prep"),
|
||||||
"cd {}/model; {} -ql design_{s}.log design_{s}.ys".format(self.workdir, self.exe_paths["yosys"], s=model_name)
|
"cd {}/model; {} -ql design_{s}.log design_{s}.ys".format(self.workdir, self.exe_paths["yosys"], s=model_name)
|
||||||
)
|
)
|
||||||
proc.checkretcode = True
|
proc.checkretcode = True
|
||||||
|
@ -707,9 +724,8 @@ class SbyTask(SbyConfig):
|
||||||
if model_name == "aig":
|
if model_name == "aig":
|
||||||
with open(f"{self.workdir}/model/design_aiger.ys", "w") as f:
|
with open(f"{self.workdir}/model/design_aiger.ys", "w") as f:
|
||||||
print(f"# running in {self.workdir}/model/", file=f)
|
print(f"# running in {self.workdir}/model/", file=f)
|
||||||
print("read_ilang design.il", file=f)
|
print("read_ilang design_prep.il", file=f)
|
||||||
print("memory_map", file=f)
|
print("hierarchy -simcheck", file=f)
|
||||||
print_common_prep("-simcheck")
|
|
||||||
print("flatten", file=f)
|
print("flatten", file=f)
|
||||||
print("setundef -undriven -anyseq", file=f)
|
print("setundef -undriven -anyseq", file=f)
|
||||||
print("setattr -unset keep", file=f)
|
print("setattr -unset keep", file=f)
|
||||||
|
@ -717,23 +733,26 @@ class SbyTask(SbyConfig):
|
||||||
print("opt -full", file=f)
|
print("opt -full", file=f)
|
||||||
print("techmap", file=f)
|
print("techmap", file=f)
|
||||||
print("opt -fast", file=f)
|
print("opt -fast", file=f)
|
||||||
|
print("memory_map -formal", file=f)
|
||||||
|
print("formalff -clk2ff -ff2anyinit", file=f)
|
||||||
|
print("simplemap", file=f)
|
||||||
print("dffunmap", file=f)
|
print("dffunmap", file=f)
|
||||||
print("abc -g AND -fast", file=f)
|
print("abc -g AND -fast", file=f)
|
||||||
print("opt_clean", file=f)
|
print("opt_clean", file=f)
|
||||||
print("stat", file=f)
|
print("stat", file=f)
|
||||||
print("write_aiger -I -B -zinit -no-startoffset -map design_aiger.aim design_aiger.aig", file=f)
|
print("write_aiger -I -B -zinit -no-startoffset -map design_aiger.aim -ywmap design_aiger.ywa design_aiger.aig", file=f)
|
||||||
|
|
||||||
proc = SbyProc(
|
proc = SbyProc(
|
||||||
self,
|
self,
|
||||||
"aig",
|
"aig",
|
||||||
self.model("base"),
|
self.model("prep"),
|
||||||
f"""cd {self.workdir}/model; {self.exe_paths["yosys"]} -ql design_aiger.log design_aiger.ys"""
|
f"""cd {self.workdir}/model; {self.exe_paths["yosys"]} -ql design_aiger.log design_aiger.ys"""
|
||||||
)
|
)
|
||||||
proc.checkretcode = True
|
proc.checkretcode = True
|
||||||
|
|
||||||
return [proc]
|
return [proc]
|
||||||
|
|
||||||
assert False
|
self.error(f"Invalid model name: {model_name}")
|
||||||
|
|
||||||
def model(self, model_name):
|
def model(self, model_name):
|
||||||
if model_name not in self.models:
|
if model_name not in self.models:
|
||||||
|
@ -811,6 +830,8 @@ class SbyTask(SbyConfig):
|
||||||
self.handle_int_option("skip", None)
|
self.handle_int_option("skip", None)
|
||||||
self.handle_str_option("tbtop", None)
|
self.handle_str_option("tbtop", None)
|
||||||
|
|
||||||
|
self.handle_str_option("make_model", None)
|
||||||
|
|
||||||
def setup_procs(self, setupmode):
|
def setup_procs(self, setupmode):
|
||||||
self.handle_non_engine_options()
|
self.handle_non_engine_options()
|
||||||
if self.opt_smtc is not None:
|
if self.opt_smtc is not None:
|
||||||
|
@ -838,6 +859,13 @@ class SbyTask(SbyConfig):
|
||||||
self.retcode = 0
|
self.retcode = 0
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if self.opt_make_model is not None:
|
||||||
|
for name in self.opt_make_model.split(","):
|
||||||
|
self.model(name.strip())
|
||||||
|
|
||||||
|
for proc in self.procs_pending:
|
||||||
|
proc.wait = True
|
||||||
|
|
||||||
if self.opt_mode == "bmc":
|
if self.opt_mode == "bmc":
|
||||||
import sby_mode_bmc
|
import sby_mode_bmc
|
||||||
sby_mode_bmc.run(self)
|
sby_mode_bmc.run(self)
|
||||||
|
@ -906,6 +934,8 @@ class SbyTask(SbyConfig):
|
||||||
|
|
||||||
def print_junit_result(self, f, junit_ts_name, junit_tc_name, junit_format_strict=False):
|
def print_junit_result(self, f, junit_ts_name, junit_tc_name, junit_format_strict=False):
|
||||||
junit_time = strftime('%Y-%m-%dT%H:%M:%S')
|
junit_time = strftime('%Y-%m-%dT%H:%M:%S')
|
||||||
|
if not self.design:
|
||||||
|
self.precise_prop_status = False
|
||||||
if self.precise_prop_status:
|
if self.precise_prop_status:
|
||||||
checks = self.design.hierarchy.get_property_list()
|
checks = self.design.hierarchy.get_property_list()
|
||||||
junit_tests = len(checks)
|
junit_tests = len(checks)
|
||||||
|
|
|
@ -111,7 +111,7 @@ def run(mode, task, engine_idx, engine):
|
||||||
f"engine_{engine_idx}",
|
f"engine_{engine_idx}",
|
||||||
task.model("smt2"),
|
task.model("smt2"),
|
||||||
("cd {}; {} -g -s {}{} --noprogress --dump-vcd engine_{i}/trace.vcd --dump-vlogtb engine_{i}/trace_tb.v " +
|
("cd {}; {} -g -s {}{} --noprogress --dump-vcd engine_{i}/trace.vcd --dump-vlogtb engine_{i}/trace_tb.v " +
|
||||||
"--dump-smtc engine_{i}/trace.smtc --aig model/design_aiger.aim:engine_{i}/trace.aiw model/design_smt2.smt2").format
|
"--dump-smtc engine_{i}/trace.smtc --dump-yw engine_{i}/trace.yw --aig model/design_aiger.aim:engine_{i}/trace.aiw model/design_smt2.smt2").format
|
||||||
(task.workdir, task.exe_paths["smtbmc"], task.opt_aigsmt,
|
(task.workdir, task.exe_paths["smtbmc"], task.opt_aigsmt,
|
||||||
"" if task.opt_tbtop is None else f" --vlogtb-top {task.opt_tbtop}",
|
"" if task.opt_tbtop is None else f" --vlogtb-top {task.opt_tbtop}",
|
||||||
i=engine_idx),
|
i=engine_idx),
|
||||||
|
@ -123,7 +123,7 @@ def run(mode, task, engine_idx, engine):
|
||||||
f"engine_{engine_idx}",
|
f"engine_{engine_idx}",
|
||||||
task.model("smt2"),
|
task.model("smt2"),
|
||||||
("cd {}; {} -s {}{} --noprogress --append {} --dump-vcd engine_{i}/trace.vcd --dump-vlogtb engine_{i}/trace_tb.v " +
|
("cd {}; {} -s {}{} --noprogress --append {} --dump-vcd engine_{i}/trace.vcd --dump-vlogtb engine_{i}/trace_tb.v " +
|
||||||
"--dump-smtc engine_{i}/trace.smtc --aig model/design_aiger.aim:engine_{i}/trace.aiw model/design_smt2.smt2").format
|
"--dump-smtc engine_{i}/trace.smtc --dump-yw engine_{i}/trace.yw --aig model/design_aiger.aim:engine_{i}/trace.aiw model/design_smt2.smt2").format
|
||||||
(task.workdir, task.exe_paths["smtbmc"], task.opt_aigsmt,
|
(task.workdir, task.exe_paths["smtbmc"], task.opt_aigsmt,
|
||||||
"" if task.opt_tbtop is None else f" --vlogtb-top {task.opt_tbtop}",
|
"" if task.opt_tbtop is None else f" --vlogtb-top {task.opt_tbtop}",
|
||||||
task.opt_append, i=engine_idx),
|
task.opt_append, i=engine_idx),
|
||||||
|
|
|
@ -152,7 +152,7 @@ def run(mode, task, engine_idx, engine):
|
||||||
task,
|
task,
|
||||||
procname,
|
procname,
|
||||||
task.model(model_name),
|
task.model(model_name),
|
||||||
f"""cd {task.workdir}; {task.exe_paths["smtbmc"]} {" ".join(smtbmc_opts)} -t {t_opt} {random_seed} --append {task.opt_append} --dump-vcd {trace_prefix}.vcd --dump-vlogtb {trace_prefix}_tb.v --dump-smtc {trace_prefix}.smtc model/design_{model_name}.smt2""",
|
f"""cd {task.workdir}; {task.exe_paths["smtbmc"]} {" ".join(smtbmc_opts)} -t {t_opt} {random_seed} --append {task.opt_append} --dump-vcd {trace_prefix}.vcd --dump-yw {trace_prefix}.yw --dump-vlogtb {trace_prefix}_tb.v --dump-smtc {trace_prefix}.smtc model/design_{model_name}.smt2""",
|
||||||
logfile=open(logfile_prefix + ".txt", "w"),
|
logfile=open(logfile_prefix + ".txt", "w"),
|
||||||
logstderr=(not progress)
|
logstderr=(not progress)
|
||||||
)
|
)
|
||||||
|
|
|
@ -46,5 +46,8 @@ def run(task):
|
||||||
import sby_engine_btor
|
import sby_engine_btor
|
||||||
sby_engine_btor.run("bmc", task, engine_idx, engine)
|
sby_engine_btor.run("bmc", task, engine_idx, engine)
|
||||||
|
|
||||||
|
elif engine[0] == "none":
|
||||||
|
pass
|
||||||
|
|
||||||
else:
|
else:
|
||||||
task.error(f"Invalid engine '{engine[0]}' for bmc mode.")
|
task.error(f"Invalid engine '{engine[0]}' for bmc mode.")
|
||||||
|
|
|
@ -37,5 +37,8 @@ def run(task):
|
||||||
import sby_engine_btor
|
import sby_engine_btor
|
||||||
sby_engine_btor.run("cover", task, engine_idx, engine)
|
sby_engine_btor.run("cover", task, engine_idx, engine)
|
||||||
|
|
||||||
|
elif engine[0] == "none":
|
||||||
|
pass
|
||||||
|
|
||||||
else:
|
else:
|
||||||
task.error(f"Invalid engine '{engine[0]}' for cover mode.")
|
task.error(f"Invalid engine '{engine[0]}' for cover mode.")
|
||||||
|
|
|
@ -34,5 +34,8 @@ def run(task):
|
||||||
import sby_engine_aiger
|
import sby_engine_aiger
|
||||||
sby_engine_aiger.run("live", task, engine_idx, engine)
|
sby_engine_aiger.run("live", task, engine_idx, engine)
|
||||||
|
|
||||||
|
elif engine[0] == "none":
|
||||||
|
pass
|
||||||
|
|
||||||
else:
|
else:
|
||||||
task.error(f"Invalid engine '{engine[0]}' for live mode.")
|
task.error(f"Invalid engine '{engine[0]}' for live mode.")
|
||||||
|
|
|
@ -49,5 +49,8 @@ def run(task):
|
||||||
import sby_engine_abc
|
import sby_engine_abc
|
||||||
sby_engine_abc.run("prove", task, engine_idx, engine)
|
sby_engine_abc.run("prove", task, engine_idx, engine)
|
||||||
|
|
||||||
|
elif engine[0] == "none":
|
||||||
|
pass
|
||||||
|
|
||||||
else:
|
else:
|
||||||
task.error(f"Invalid engine '{engine[0]}' for prove mode.")
|
task.error(f"Invalid engine '{engine[0]}' for prove mode.")
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
module test (input CP, CN, CX, input A, B, output reg XP, XN, YP, YN);
|
module test (input CP, CN, input A, B, output reg XP, XN);
|
||||||
|
reg [7:0] counter = 0;
|
||||||
always @* begin
|
always @* begin
|
||||||
assume (A || B);
|
assume (A || B);
|
||||||
assume (!A || !B);
|
assume (!A || !B);
|
||||||
assert (A != B);
|
assert (A != B);
|
||||||
cover (A);
|
cover (counter == 3 && A);
|
||||||
cover (B);
|
cover (counter == 3 && B);
|
||||||
end
|
end
|
||||||
|
always @(posedge CP)
|
||||||
|
counter <= counter + 1;
|
||||||
always @(posedge CP)
|
always @(posedge CP)
|
||||||
XP <= A;
|
XP <= A;
|
||||||
always @(negedge CN)
|
always @(negedge CN)
|
||||||
XN <= B;
|
XN <= B;
|
||||||
always @(posedge CX)
|
|
||||||
YP <= A;
|
|
||||||
always @(negedge CX)
|
|
||||||
YN <= B;
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
Loading…
Reference in a new issue