mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-06 14:13:23 +00:00
Merge branch 'master' into mwk/xilinx_bufgmap
This commit is contained in:
commit
a098205479
8 changed files with 405 additions and 60 deletions
118
CHANGELOG
118
CHANGELOG
|
@ -12,7 +12,10 @@ Yosys 0.9 .. Yosys 0.9-dev
|
||||||
- Added "synth_xilinx -abc9" (experimental)
|
- Added "synth_xilinx -abc9" (experimental)
|
||||||
- Added "synth_ice40 -abc9" (experimental)
|
- Added "synth_ice40 -abc9" (experimental)
|
||||||
- Added "synth -abc9" (experimental)
|
- Added "synth -abc9" (experimental)
|
||||||
- Added "script -scriptwire
|
- Added "script -scriptwire"
|
||||||
|
- Added "synth_xilinx -nocarry"
|
||||||
|
- Added "synth_xilinx -nowidelut"
|
||||||
|
- Added "synth_ecp5 -nowidelut"
|
||||||
- "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable)
|
- "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable)
|
||||||
- Renamed labels/options in synth_ice40 (e.g. dram -> map_lutram; -nodram -> -nolutram)
|
- Renamed labels/options in synth_ice40 (e.g. dram -> map_lutram; -nodram -> -nolutram)
|
||||||
- Renamed labels/options in synth_ecp5 (e.g. dram -> map_lutram; -nodram -> -nolutram)
|
- Renamed labels/options in synth_ecp5 (e.g. dram -> map_lutram; -nodram -> -nolutram)
|
||||||
|
@ -32,33 +35,126 @@ Yosys 0.9 .. Yosys 0.9-dev
|
||||||
- Added "opt_share" pass, run as part of "opt -full"
|
- Added "opt_share" pass, run as part of "opt -full"
|
||||||
- Added "ice40_wrapcarry" to encapsulate SB_LUT+SB_CARRY pairs for techmapping
|
- Added "ice40_wrapcarry" to encapsulate SB_LUT+SB_CARRY pairs for techmapping
|
||||||
- Removed "ice40_unlut"
|
- Removed "ice40_unlut"
|
||||||
|
- Improvements in pmgen: slices, choices, define, generate
|
||||||
|
|
||||||
Yosys 0.8 .. Yosys 0.8-dev
|
Yosys 0.8 .. Yosys 0.9
|
||||||
--------------------------
|
----------------------
|
||||||
|
|
||||||
* Various
|
* Various
|
||||||
- Added $changed support to read_verilog
|
- Many bugfixes and small improvements
|
||||||
|
- Added support for SystemVerilog interfaces and modports
|
||||||
- Added "write_edif -attrprop"
|
- Added "write_edif -attrprop"
|
||||||
- Added "ice40_unlut" pass
|
|
||||||
- Added "opt_lut" pass
|
- Added "opt_lut" pass
|
||||||
- Added "synth_ice40 -relut"
|
|
||||||
- Added "synth_ice40 -noabc"
|
|
||||||
- Added "gate2lut.v" techmap rule
|
- Added "gate2lut.v" techmap rule
|
||||||
- Added "rename -src"
|
- Added "rename -src"
|
||||||
- Added "equiv_opt" pass
|
- Added "equiv_opt" pass
|
||||||
- Added "shregmap -tech xilinx"
|
- Added "flowmap" LUT mapping pass
|
||||||
|
- Added "rename -wire" to rename cells based on the wires they drive
|
||||||
|
- Added "bugpoint" for creating minimised testcases
|
||||||
|
- Added "write_edif -gndvccy"
|
||||||
|
- "write_verilog" to escape Verilog keywords
|
||||||
|
- Fixed sign handling of real constants
|
||||||
|
- "write_verilog" to write initial statement for initial flop state
|
||||||
|
- Added pmgen pattern matcher generator
|
||||||
|
- Fixed opt_rmdff handling of $_DFFSR_???_ and $_DLATCHSR_???_
|
||||||
|
- Added "setundef -params" to replace undefined cell parameters
|
||||||
|
- Renamed "yosys -D" to "yosys -U", added "yosys -D" to set Verilog defines
|
||||||
|
- Fixed handling of defparam when default_nettype is none
|
||||||
|
- Fixed "wreduce" flipflop handling
|
||||||
|
- Fixed FIRRTL to Verilog process instance subfield assignment
|
||||||
|
- Added "write_verilog -siminit"
|
||||||
|
- Several fixes and improvements for mem2reg memories
|
||||||
|
- Fixed handling of task output ports in clocked always blocks
|
||||||
|
- Improved handling of and-with-1 and or-with-0 in "opt_expr"
|
||||||
- Added "read_aiger" frontend
|
- Added "read_aiger" frontend
|
||||||
|
- Added "mutate" pass
|
||||||
|
- Added "hdlname" attribute
|
||||||
|
- Added "rename -output"
|
||||||
|
- Added "read_ilang -lib"
|
||||||
|
- Improved "proc" full_case detection and handling
|
||||||
|
- Added "whitebox" and "lib_whitebox" attributes
|
||||||
|
- Added "read_verilog -nowb", "flatten -wb" and "wbflip"
|
||||||
|
- Added Python bindings and support for Python plug-ins
|
||||||
|
- Added "pmux2shiftx"
|
||||||
|
- Added log_debug framework for reduced default verbosity
|
||||||
|
- Improved "opt_expr" and "opt_clean" handling of (partially) undriven and/or unused wires
|
||||||
|
- Added "peepopt" peephole optimisation pass using pmgen
|
||||||
|
- Added approximate support for SystemVerilog "var" keyword
|
||||||
|
- Added parsing of "specify" blocks into $specrule and $specify[23]
|
||||||
|
- Added support for attributes on parameters and localparams
|
||||||
|
- Added support for parsing attributes on port connections
|
||||||
|
- Added "wreduce -keepdc"
|
||||||
|
- Added support for optimising $dffe and $_DFFE_* cells in "opt_rmdff"
|
||||||
|
- Added Verilog wand/wor wire type support
|
||||||
|
- Added support for elaboration system tasks
|
||||||
- Added "muxcover -mux{4,8,16}=<cost>"
|
- Added "muxcover -mux{4,8,16}=<cost>"
|
||||||
- Added "muxcover -dmux=<cost>"
|
- Added "muxcover -dmux=<cost>"
|
||||||
- Added "muxcover -nopartial"
|
- Added "muxcover -nopartial"
|
||||||
- Added "muxpack" pass
|
- Added "muxpack" pass
|
||||||
- Added "pmux2shiftx -norange"
|
- Added "pmux2shiftx -norange"
|
||||||
|
- Added support for "~" in filename parsing
|
||||||
|
- Added "read_verilog -pwires" feature to turn parameters into wires
|
||||||
|
- Fixed sign extension of unsized constants with 'bx and 'bz MSB
|
||||||
|
- Fixed genvar to be a signed type
|
||||||
|
- Added support for attributes on case rules
|
||||||
|
- Added "upto" and "offset" to JSON frontend and backend
|
||||||
|
- Several liberty file parser improvements
|
||||||
|
- Fixed handling of more complex BRAM patterns
|
||||||
|
- Add "write_aiger -I -O -B"
|
||||||
|
|
||||||
|
* Formal Verification
|
||||||
|
- Added $changed support to read_verilog
|
||||||
|
- Added "read_verilog -noassert -noassume -assert-assumes"
|
||||||
|
- Added btor ops for $mul, $div, $mod and $concat
|
||||||
|
- Added yosys-smtbmc support for btor witnesses
|
||||||
|
- Added "supercover" pass
|
||||||
|
- Fixed $global_clock handling vs autowire
|
||||||
|
- Added $dffsr support to "async2sync"
|
||||||
|
- Added "fmcombine" pass
|
||||||
|
- Added memory init support in "write_btor"
|
||||||
|
- Added "cutpoint" pass
|
||||||
|
- Changed "ne" to "neq" in btor2 output
|
||||||
|
- Added support for SVA "final" keyword
|
||||||
|
- Added "fmcombine -initeq -anyeq"
|
||||||
|
- Added timescale and generated-by header to yosys-smtbmc vcd output
|
||||||
|
- Improved BTOR2 handling of undriven wires
|
||||||
|
|
||||||
|
* Verific support
|
||||||
|
- Enabled Verific flags vhdl_support_variable_slice and veri_elaborate_top_level_modules_having_interface_ports
|
||||||
|
- Improved support for asymmetric memories
|
||||||
|
- Added "verific -chparam"
|
||||||
|
- Fixed "verific -extnets" for more complex situations
|
||||||
|
- Added "read -verific" and "read -noverific"
|
||||||
|
- Added "hierarchy -chparam"
|
||||||
|
|
||||||
|
* New back-ends
|
||||||
|
- Added initial Anlogic support
|
||||||
|
- Added initial SmartFusion2 and IGLOO2 support
|
||||||
|
|
||||||
|
* ECP5 support
|
||||||
|
- Added "synth_ecp5 -nowidelut"
|
||||||
|
- Added BRAM inference support to "synth_ecp5"
|
||||||
|
- Added support for transforming Diamond IO and flipflop primitives
|
||||||
|
|
||||||
|
* iCE40 support
|
||||||
|
- Added "ice40_unlut" pass
|
||||||
|
- Added "synth_ice40 -relut"
|
||||||
|
- Added "synth_ice40 -noabc"
|
||||||
|
- Added "synth_ice40 -dffe_min_ce_use"
|
||||||
|
- Added DSP inference support using pmgen
|
||||||
|
- Added support for initialising BRAM primitives from a file
|
||||||
|
- Added iCE40 Ultra RGB LED driver cells
|
||||||
|
|
||||||
|
* Xilinx support
|
||||||
|
- Use "write_edif -pvector bra" for Xilinx EDIF files
|
||||||
|
- Fixes for VPR place and route support with "synth_xilinx"
|
||||||
|
- Added more cell simulation models
|
||||||
|
- Added "synth_xilinx -family"
|
||||||
|
- Added "stat -tech xilinx" to estimate logic cell usage
|
||||||
- Added "synth_xilinx -nocarry"
|
- Added "synth_xilinx -nocarry"
|
||||||
- Added "synth_xilinx -nowidelut"
|
- Added "synth_xilinx -nowidelut"
|
||||||
- Added "synth_ecp5 -nowidelut"
|
|
||||||
- "synth_xilinx" to now infer hard shift registers (-nosrl to disable)
|
- "synth_xilinx" to now infer hard shift registers (-nosrl to disable)
|
||||||
- Fixed sign extension of unsized constants with 'bx and 'bz MSB
|
- Added support for mapping RAM32X1D
|
||||||
|
|
||||||
|
|
||||||
Yosys 0.7 .. Yosys 0.8
|
Yosys 0.7 .. Yosys 0.8
|
||||||
----------------------
|
----------------------
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -115,7 +115,7 @@ LDFLAGS += -rdynamic
|
||||||
LDLIBS += -lrt
|
LDLIBS += -lrt
|
||||||
endif
|
endif
|
||||||
|
|
||||||
YOSYS_VER := 0.8+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 4d4665b.. 2> /dev/null | wc -l; })
|
YOSYS_VER := 0.9+1
|
||||||
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
|
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
|
||||||
OBJS = kernel/version_$(GIT_REV).o
|
OBJS = kernel/version_$(GIT_REV).o
|
||||||
|
|
||||||
|
|
|
@ -508,23 +508,17 @@ class TupleTranslator(PythonDictTranslator):
|
||||||
#Generate c++ code to translate to a boost::python::tuple
|
#Generate c++ code to translate to a boost::python::tuple
|
||||||
@classmethod
|
@classmethod
|
||||||
def translate_cpp(c, varname, types, prefix, ref):
|
def translate_cpp(c, varname, types, prefix, ref):
|
||||||
text = prefix + TupleTranslator.typename + " " + varname + "___tmp = boost::python::make_tuple(" + varname + ".first, " + varname + ".second);"
|
# if the tuple is a pair of SigSpecs (aka SigSig), then we need
|
||||||
return text
|
# to call get_py_obj() on each item in the tuple
|
||||||
tmp_name = "tmp_" + str(Translator.tmp_cntr)
|
if types[0].name in classnames:
|
||||||
Translator.tmp_cntr = Translator.tmp_cntr + 1
|
first_var = types[0].name + "::get_py_obj(" + varname + ".first)"
|
||||||
if ref:
|
|
||||||
text += prefix + "for(auto " + tmp_name + " : *" + varname + ")"
|
|
||||||
else:
|
else:
|
||||||
text += prefix + "for(auto " + tmp_name + " : " + varname + ")"
|
first_var = varname + ".first"
|
||||||
text += prefix + "{"
|
if types[1].name in classnames:
|
||||||
if types[0].name.split(" ")[-1] in primitive_types or types[0].name in enum_names:
|
second_var = types[1].name + "::get_py_obj(" + varname + ".second)"
|
||||||
text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + ");"
|
else:
|
||||||
elif types[0].name in known_containers:
|
second_var = varname + ".second"
|
||||||
text += known_containers[types[0].name].translate_cpp(tmp_name, types[0].cont.args, prefix + "\t", types[1].attr_type == attr_types.star)
|
text = prefix + TupleTranslator.typename + " " + varname + "___tmp = boost::python::make_tuple(" + first_var + ", " + second_var + ");"
|
||||||
text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "___tmp);"
|
|
||||||
elif types[0].name in classnames:
|
|
||||||
text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "));"
|
|
||||||
text += prefix + "}"
|
|
||||||
return text
|
return text
|
||||||
|
|
||||||
#Associate the Translators with their c++ type
|
#Associate the Translators with their c++ type
|
||||||
|
|
|
@ -178,6 +178,45 @@ evaluates to `false`.
|
||||||
The `semioptional` statement marks matches that must match if at least one
|
The `semioptional` statement marks matches that must match if at least one
|
||||||
matching cell exists, but if no matching cell exists it is set to `nullptr`.
|
matching cell exists, but if no matching cell exists it is set to `nullptr`.
|
||||||
|
|
||||||
|
Slices and choices
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Cell matches can contain "slices" and "choices". Slices can be used to
|
||||||
|
create matches for different sections of a cell. For example:
|
||||||
|
|
||||||
|
state <int> pmux_slice
|
||||||
|
|
||||||
|
match pmux
|
||||||
|
select pmux->type == $pmux
|
||||||
|
slice idx GetSize(port(pmux, \S))
|
||||||
|
index <SigBit> port(pmux, \S)[idx] === port(eq, \Y)
|
||||||
|
set pmux_slice idx
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
The first argument to `slice` is the local variable name used to identify the
|
||||||
|
slice. The second argument is the number of slices that should be created for
|
||||||
|
this cell. The `set` statement can be used to copy that index into a state
|
||||||
|
variable so that later matches and/or code blocks can refer to it.
|
||||||
|
|
||||||
|
A similar mechanism is "choices", where a list of options is given as
|
||||||
|
second argument, and the matcher will iterate over those options:
|
||||||
|
|
||||||
|
state <SigSpec> foo bar
|
||||||
|
state <IdString> eq_ab eq_ba
|
||||||
|
|
||||||
|
match eq
|
||||||
|
select eq->type == $eq
|
||||||
|
choice <IdString> AB {\A, \B}
|
||||||
|
define <IdString> BA (AB == \A ? \B : \A)
|
||||||
|
index <SigSpec> port(eq, AB) === foo
|
||||||
|
index <SigSpec> port(eq, BA) === bar
|
||||||
|
set eq_ab AB
|
||||||
|
set eq_ba BA
|
||||||
|
generate
|
||||||
|
|
||||||
|
Notice how `define` can be used to define additional local variables similar
|
||||||
|
to the loop variables defined by `slice` and `choice`.
|
||||||
|
|
||||||
Additional code
|
Additional code
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -326,7 +365,7 @@ test-case generation. For example:
|
||||||
|
|
||||||
match mul
|
match mul
|
||||||
...
|
...
|
||||||
generate 10
|
generate 10 0
|
||||||
SigSpec Y = port(ff, \D);
|
SigSpec Y = port(ff, \D);
|
||||||
SigSpec A = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2));
|
SigSpec A = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2));
|
||||||
SigSpec B = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2));
|
SigSpec B = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2));
|
||||||
|
@ -335,8 +374,11 @@ test-case generation. For example:
|
||||||
|
|
||||||
The expression `rng(n)` returns a non-negative integer less than `n`.
|
The expression `rng(n)` returns a non-negative integer less than `n`.
|
||||||
|
|
||||||
The argument to `generate` is the chance of this generate block being executed
|
The first argument to `generate` is the chance of this generate block being
|
||||||
when the match block did not match anything, in percent.
|
executed when the match block did not match anything, in percent.
|
||||||
|
|
||||||
|
The second argument to `generate` is the chance of this generate block being
|
||||||
|
executed when the match block did match something, in percent.
|
||||||
|
|
||||||
The special statement `finish` can be used within generate blocks to terminate
|
The special statement `finish` can be used within generate blocks to terminate
|
||||||
the current pattern matcher run.
|
the current pattern matcher run.
|
||||||
|
|
|
@ -207,9 +207,10 @@ def process_pmgfile(f, filename):
|
||||||
state_types[current_pattern][line[1]] = "Cell*";
|
state_types[current_pattern][line[1]] = "Cell*";
|
||||||
|
|
||||||
block["if"] = list()
|
block["if"] = list()
|
||||||
block["select"] = list()
|
block["setup"] = list()
|
||||||
block["index"] = list()
|
block["index"] = list()
|
||||||
block["filter"] = list()
|
block["filter"] = list()
|
||||||
|
block["sets"] = list()
|
||||||
block["optional"] = False
|
block["optional"] = False
|
||||||
block["semioptional"] = False
|
block["semioptional"] = False
|
||||||
|
|
||||||
|
@ -228,7 +229,22 @@ def process_pmgfile(f, filename):
|
||||||
|
|
||||||
if a[0] == "select":
|
if a[0] == "select":
|
||||||
b = l.lstrip()[6:]
|
b = l.lstrip()[6:]
|
||||||
block["select"].append(rewrite_cpp(b.strip()))
|
block["setup"].append(("select", rewrite_cpp(b.strip())))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if a[0] == "slice":
|
||||||
|
m = re.match(r"^\s*slice\s+(\S+)\s+(.*?)\s*$", l)
|
||||||
|
block["setup"].append(("slice", m.group(1), rewrite_cpp(m.group(2))))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if a[0] == "choice":
|
||||||
|
m = re.match(r"^\s*choice\s+<(.*?)>\s+(\S+)\s+(.*?)\s*$", l)
|
||||||
|
block["setup"].append(("choice", m.group(1), m.group(2), rewrite_cpp(m.group(3))))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if a[0] == "define":
|
||||||
|
m = re.match(r"^\s*define\s+<(.*?)>\s+(\S+)\s+(.*?)\s*$", l)
|
||||||
|
block["setup"].append(("define", m.group(1), m.group(2), rewrite_cpp(m.group(3))))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if a[0] == "index":
|
if a[0] == "index":
|
||||||
|
@ -242,6 +258,11 @@ def process_pmgfile(f, filename):
|
||||||
block["filter"].append(rewrite_cpp(b.strip()))
|
block["filter"].append(rewrite_cpp(b.strip()))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if a[0] == "set":
|
||||||
|
m = re.match(r"^\s*set\s+(\S+)\s+(.*?)\s*$", l)
|
||||||
|
block["sets"].append((m.group(1), rewrite_cpp(m.group(2))))
|
||||||
|
continue
|
||||||
|
|
||||||
if a[0] == "optional":
|
if a[0] == "optional":
|
||||||
block["optional"] = True
|
block["optional"] = True
|
||||||
continue
|
continue
|
||||||
|
@ -252,14 +273,16 @@ def process_pmgfile(f, filename):
|
||||||
|
|
||||||
if a[0] == "generate":
|
if a[0] == "generate":
|
||||||
block["genargs"] = list([int(s) for s in a[1:]])
|
block["genargs"] = list([int(s) for s in a[1:]])
|
||||||
|
if len(block["genargs"]) == 0: block["genargs"].append(100)
|
||||||
|
if len(block["genargs"]) == 1: block["genargs"].append(0)
|
||||||
|
assert len(block["genargs"]) == 2
|
||||||
block["gencode"] = list()
|
block["gencode"] = list()
|
||||||
assert len(block["genargs"]) < 2
|
|
||||||
while True:
|
while True:
|
||||||
linenr += 1
|
linenr += 1
|
||||||
l = f.readline()
|
l = f.readline()
|
||||||
assert l != ""
|
assert l != ""
|
||||||
a = l.split()
|
a = l.split()
|
||||||
if a[0] == "endmatch": break
|
if len(a) == 1 and a[0] == "endmatch": break
|
||||||
block["gencode"].append(rewrite_cpp(l.rstrip()))
|
block["gencode"].append(rewrite_cpp(l.rstrip()))
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -357,8 +380,17 @@ with open(outfile, "w") as f:
|
||||||
index_types = list()
|
index_types = list()
|
||||||
for entry in block["index"]:
|
for entry in block["index"]:
|
||||||
index_types.append(entry[0])
|
index_types.append(entry[0])
|
||||||
|
value_types = ["Cell*"]
|
||||||
|
for entry in block["setup"]:
|
||||||
|
if entry[0] == "slice":
|
||||||
|
value_types.append("int")
|
||||||
|
if entry[0] == "choice":
|
||||||
|
value_types.append(entry[1])
|
||||||
|
if entry[0] == "define":
|
||||||
|
value_types.append(entry[1])
|
||||||
print(" typedef std::tuple<{}> index_{}_key_type;".format(", ".join(index_types), index), file=f)
|
print(" typedef std::tuple<{}> index_{}_key_type;".format(", ".join(index_types), index), file=f)
|
||||||
print(" dict<index_{}_key_type, vector<Cell*>> index_{};".format(index, index), file=f)
|
print(" typedef std::tuple<{}> index_{}_value_type;".format(", ".join(value_types), index), file=f)
|
||||||
|
print(" dict<index_{}_key_type, vector<index_{}_value_type>> index_{};".format(index, index, index), file=f)
|
||||||
print(" dict<SigBit, pool<Cell*>> sigusers;", file=f)
|
print(" dict<SigBit, pool<Cell*>> sigusers;", file=f)
|
||||||
print(" pool<Cell*> blacklist_cells;", file=f)
|
print(" pool<Cell*> blacklist_cells;", file=f)
|
||||||
print(" pool<Cell*> autoremove_cells;", file=f)
|
print(" pool<Cell*> autoremove_cells;", file=f)
|
||||||
|
@ -390,8 +422,6 @@ with open(outfile, "w") as f:
|
||||||
print(" void add_siguser(const SigSpec &sig, Cell *cell) {", file=f)
|
print(" void add_siguser(const SigSpec &sig, Cell *cell) {", file=f)
|
||||||
print(" for (auto bit : sigmap(sig)) {", file=f)
|
print(" for (auto bit : sigmap(sig)) {", file=f)
|
||||||
print(" if (bit.wire == nullptr) continue;", file=f)
|
print(" if (bit.wire == nullptr) continue;", file=f)
|
||||||
print(" if (sigusers.count(bit) == 0 && bit.wire->port_id)", file=f)
|
|
||||||
print(" sigusers[bit].insert(nullptr);", file=f)
|
|
||||||
print(" sigusers[bit].insert(cell);", file=f)
|
print(" sigusers[bit].insert(cell);", file=f)
|
||||||
print(" }", file=f)
|
print(" }", file=f)
|
||||||
print(" }", file=f)
|
print(" }", file=f)
|
||||||
|
@ -446,10 +476,11 @@ with open(outfile, "w") as f:
|
||||||
else:
|
else:
|
||||||
print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f)
|
print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f)
|
||||||
current_pattern = None
|
current_pattern = None
|
||||||
print(" for (auto cell : module->cells()) {", file=f)
|
print(" for (auto port : module->ports)", file=f)
|
||||||
|
print(" add_siguser(module->wire(port), nullptr);", file=f)
|
||||||
|
print(" for (auto cell : module->cells())", file=f)
|
||||||
print(" for (auto &conn : cell->connections())", file=f)
|
print(" for (auto &conn : cell->connections())", file=f)
|
||||||
print(" add_siguser(conn.second, cell);", file=f)
|
print(" add_siguser(conn.second, cell);", file=f)
|
||||||
print(" }", file=f)
|
|
||||||
print(" for (auto cell : cells) {", file=f)
|
print(" for (auto cell : cells) {", file=f)
|
||||||
|
|
||||||
for index in range(len(blocks)):
|
for index in range(len(blocks)):
|
||||||
|
@ -457,12 +488,34 @@ with open(outfile, "w") as f:
|
||||||
if block["type"] == "match":
|
if block["type"] == "match":
|
||||||
print(" do {", file=f)
|
print(" do {", file=f)
|
||||||
print(" Cell *{} = cell;".format(block["cell"]), file=f)
|
print(" Cell *{} = cell;".format(block["cell"]), file=f)
|
||||||
for expr in block["select"]:
|
print(" index_{}_value_type value;".format(index), file=f)
|
||||||
print(" if (!({})) break;".format(expr), file=f)
|
print(" std::get<0>(value) = cell;", file=f)
|
||||||
|
loopcnt = 0
|
||||||
|
valueidx = 1
|
||||||
|
for item in block["setup"]:
|
||||||
|
if item[0] == "select":
|
||||||
|
print(" if (!({})) continue;".format(item[1]), file=f)
|
||||||
|
if item[0] == "slice":
|
||||||
|
print(" int &{} = std::get<{}>(value);".format(item[1], valueidx), file=f)
|
||||||
|
print(" for ({} = 0; {} < {}; {}++) {{".format(item[1], item[1], item[2], item[1]), file=f)
|
||||||
|
valueidx += 1
|
||||||
|
loopcnt += 1
|
||||||
|
if item[0] == "choice":
|
||||||
|
print(" vector<{}> _pmg_choices_{} = {};".format(item[1], item[2], item[3]), file=f)
|
||||||
|
print(" for (const {} &{} : _pmg_choices_{}) {{".format(item[1], item[2], item[2]), file=f)
|
||||||
|
print(" std::get<{}>(value) = {};".format(valueidx, item[2]), file=f)
|
||||||
|
valueidx += 1
|
||||||
|
loopcnt += 1
|
||||||
|
if item[0] == "define":
|
||||||
|
print(" {} &{} = std::get<{}>(value);".format(item[1], item[2], valueidx), file=f)
|
||||||
|
print(" {} = {};".format(item[2], item[3]), file=f)
|
||||||
|
valueidx += 1
|
||||||
print(" index_{}_key_type key;".format(index), file=f)
|
print(" index_{}_key_type key;".format(index), file=f)
|
||||||
for field, entry in enumerate(block["index"]):
|
for field, entry in enumerate(block["index"]):
|
||||||
print(" std::get<{}>(key) = {};".format(field, entry[1]), file=f)
|
print(" std::get<{}>(key) = {};".format(field, entry[1]), file=f)
|
||||||
print(" index_{}[key].push_back(cell);".format(index), file=f)
|
print(" index_{}[key].push_back(value);".format(index), file=f)
|
||||||
|
for i in range(loopcnt):
|
||||||
|
print(" }", file=f)
|
||||||
print(" } while (0);", file=f)
|
print(" } while (0);", file=f)
|
||||||
|
|
||||||
print(" }", file=f)
|
print(" }", file=f)
|
||||||
|
@ -535,6 +588,8 @@ with open(outfile, "w") as f:
|
||||||
const_st.add(s)
|
const_st.add(s)
|
||||||
elif blocks[i]["type"] == "match":
|
elif blocks[i]["type"] == "match":
|
||||||
const_st.add(blocks[i]["cell"])
|
const_st.add(blocks[i]["cell"])
|
||||||
|
for item in blocks[i]["sets"]:
|
||||||
|
const_st.add(item[0])
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
@ -548,6 +603,10 @@ with open(outfile, "w") as f:
|
||||||
s = block["cell"]
|
s = block["cell"]
|
||||||
assert s not in const_st
|
assert s not in const_st
|
||||||
nonconst_st.add(s)
|
nonconst_st.add(s)
|
||||||
|
for item in block["sets"]:
|
||||||
|
if item[0] in const_st:
|
||||||
|
const_st.remove(item[0])
|
||||||
|
nonconst_st.add(item[0])
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
@ -570,7 +629,7 @@ with open(outfile, "w") as f:
|
||||||
print("", file=f)
|
print("", file=f)
|
||||||
for s in sorted(restore_st):
|
for s in sorted(restore_st):
|
||||||
t = state_types[current_pattern][s]
|
t = state_types[current_pattern][s]
|
||||||
print(" {} backup_{} = {};".format(t, s, s), file=f)
|
print(" {} _pmg_backup_{} = {};".format(t, s, s), file=f)
|
||||||
|
|
||||||
if block["type"] == "code":
|
if block["type"] == "code":
|
||||||
print("", file=f)
|
print("", file=f)
|
||||||
|
@ -610,7 +669,7 @@ with open(outfile, "w") as f:
|
||||||
print("", file=f)
|
print("", file=f)
|
||||||
for s in sorted(restore_st):
|
for s in sorted(restore_st):
|
||||||
t = state_types[current_pattern][s]
|
t = state_types[current_pattern][s]
|
||||||
print(" {} = backup_{};".format(s, s), file=f)
|
print(" {} = _pmg_backup_{};".format(s, s), file=f)
|
||||||
for s in sorted(nonconst_st):
|
for s in sorted(nonconst_st):
|
||||||
if s not in restore_st:
|
if s not in restore_st:
|
||||||
t = state_types[current_pattern][s]
|
t = state_types[current_pattern][s]
|
||||||
|
@ -622,7 +681,7 @@ with open(outfile, "w") as f:
|
||||||
elif block["type"] == "match":
|
elif block["type"] == "match":
|
||||||
assert len(restore_st) == 0
|
assert len(restore_st) == 0
|
||||||
|
|
||||||
print(" Cell* backup_{} = {};".format(block["cell"], block["cell"]), file=f)
|
print(" Cell* _pmg_backup_{} = {};".format(block["cell"], block["cell"]), file=f)
|
||||||
|
|
||||||
if len(block["if"]):
|
if len(block["if"]):
|
||||||
for expr in block["if"]:
|
for expr in block["if"]:
|
||||||
|
@ -630,7 +689,7 @@ with open(outfile, "w") as f:
|
||||||
print(" if (!({})) {{".format(expr), file=f)
|
print(" if (!({})) {{".format(expr), file=f)
|
||||||
print(" {} = nullptr;".format(block["cell"]), file=f)
|
print(" {} = nullptr;".format(block["cell"]), file=f)
|
||||||
print(" block_{}(recursion+1);".format(index+1), file=f)
|
print(" block_{}(recursion+1);".format(index+1), file=f)
|
||||||
print(" {} = backup_{};".format(block["cell"], block["cell"]), file=f)
|
print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f)
|
||||||
print(" return;", file=f)
|
print(" return;", file=f)
|
||||||
print(" }", file=f)
|
print(" }", file=f)
|
||||||
|
|
||||||
|
@ -645,21 +704,37 @@ with open(outfile, "w") as f:
|
||||||
|
|
||||||
print("", file=f)
|
print("", file=f)
|
||||||
print(" if (cells_ptr != index_{}.end()) {{".format(index), file=f)
|
print(" if (cells_ptr != index_{}.end()) {{".format(index), file=f)
|
||||||
print(" const vector<Cell*> &cells = cells_ptr->second;".format(index), file=f)
|
print(" const vector<index_{}_value_type> &cells = cells_ptr->second;".format(index), file=f)
|
||||||
print(" for (int idx = 0; idx < GetSize(cells); idx++) {", file=f)
|
print(" for (int _pmg_idx = 0; _pmg_idx < GetSize(cells); _pmg_idx++) {", file=f)
|
||||||
print(" {} = cells[idx];".format(block["cell"]), file=f)
|
print(" {} = std::get<0>(cells[_pmg_idx]);".format(block["cell"]), file=f)
|
||||||
|
valueidx = 1
|
||||||
|
for item in block["setup"]:
|
||||||
|
if item[0] == "slice":
|
||||||
|
print(" const int &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], valueidx), file=f)
|
||||||
|
valueidx += 1
|
||||||
|
if item[0] == "choice":
|
||||||
|
print(" const {} &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f)
|
||||||
|
valueidx += 1
|
||||||
|
if item[0] == "define":
|
||||||
|
print(" const {} &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f)
|
||||||
|
valueidx += 1
|
||||||
print(" if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f)
|
print(" if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f)
|
||||||
for expr in block["filter"]:
|
for expr in block["filter"]:
|
||||||
print(" if (!({})) continue;".format(expr), file=f)
|
print(" if (!({})) continue;".format(expr), file=f)
|
||||||
if block["semioptional"] or block["genargs"] is not None:
|
if block["semioptional"] or block["genargs"] is not None:
|
||||||
print(" found_any_match = true;", file=f)
|
print(" found_any_match = true;", file=f)
|
||||||
print(" auto rollback_ptr = rollback_cache.insert(make_pair(cells[idx], recursion));", file=f)
|
for item in block["sets"]:
|
||||||
|
print(" auto _pmg_backup_{} = {};".format(item[0], item[0]), file=f)
|
||||||
|
print(" {} = {};".format(item[0], item[1]), file=f)
|
||||||
|
print(" auto rollback_ptr = rollback_cache.insert(make_pair(std::get<0>(cells[_pmg_idx]), recursion));", file=f)
|
||||||
print(" block_{}(recursion+1);".format(index+1), file=f)
|
print(" block_{}(recursion+1);".format(index+1), file=f)
|
||||||
|
for item in block["sets"]:
|
||||||
|
print(" {} = _pmg_backup_{};".format(item[0], item[0]), file=f)
|
||||||
print(" if (rollback_ptr.second)", file=f)
|
print(" if (rollback_ptr.second)", file=f)
|
||||||
print(" rollback_cache.erase(rollback_ptr.first);", file=f)
|
print(" rollback_cache.erase(rollback_ptr.first);", file=f)
|
||||||
print(" if (rollback) {", file=f)
|
print(" if (rollback) {", file=f)
|
||||||
print(" if (rollback != recursion) {{".format(index+1), file=f)
|
print(" if (rollback != recursion) {{".format(index+1), file=f)
|
||||||
print(" {} = backup_{};".format(block["cell"], block["cell"]), file=f)
|
print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f)
|
||||||
print(" return;", file=f)
|
print(" return;", file=f)
|
||||||
print(" }", file=f)
|
print(" }", file=f)
|
||||||
print(" rollback = 0;", file=f)
|
print(" rollback = 0;", file=f)
|
||||||
|
@ -676,13 +751,11 @@ with open(outfile, "w") as f:
|
||||||
if block["semioptional"]:
|
if block["semioptional"]:
|
||||||
print(" if (!found_any_match) block_{}(recursion+1);".format(index+1), file=f)
|
print(" if (!found_any_match) block_{}(recursion+1);".format(index+1), file=f)
|
||||||
|
|
||||||
print(" {} = backup_{};".format(block["cell"], block["cell"]), file=f)
|
print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f)
|
||||||
|
|
||||||
if block["genargs"] is not None:
|
if block["genargs"] is not None:
|
||||||
print("#define finish do { rollback = -1; return; } while(0)", file=f)
|
print("#define finish do { rollback = -1; return; } while(0)", file=f)
|
||||||
print(" if (generate_mode && !found_any_match) {", file=f)
|
print(" if (generate_mode && rng(100) < (found_any_match ? {} : {})) {{".format(block["genargs"][1], block["genargs"][0]), file=f)
|
||||||
if len(block["genargs"]) == 1:
|
|
||||||
print(" if (rng(100) >= {}) return;".format(block["genargs"][0]), file=f)
|
|
||||||
for line in block["gencode"]:
|
for line in block["gencode"]:
|
||||||
print(" " + line, file=f)
|
print(" " + line, file=f)
|
||||||
print(" }", file=f)
|
print(" }", file=f)
|
||||||
|
|
|
@ -99,6 +99,24 @@ void reduce_tree(test_pmgen_pm &pm)
|
||||||
log(" -> %s (%s)\n", log_id(c), log_id(c->type));
|
log(" -> %s (%s)\n", log_id(c), log_id(c->type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void opt_eqpmux(test_pmgen_pm &pm)
|
||||||
|
{
|
||||||
|
auto &st = pm.st_eqpmux;
|
||||||
|
|
||||||
|
SigSpec Y = st.pmux->getPort(ID::Y);
|
||||||
|
int width = GetSize(Y);
|
||||||
|
|
||||||
|
SigSpec EQ = st.pmux->getPort(ID::B).extract(st.pmux_slice_eq*width, width);
|
||||||
|
SigSpec NE = st.pmux->getPort(ID::B).extract(st.pmux_slice_ne*width, width);
|
||||||
|
|
||||||
|
log("Found eqpmux circuit driving %s (eq=%s, ne=%s, pmux=%s).\n",
|
||||||
|
log_signal(Y), log_id(st.eq), log_id(st.ne), log_id(st.pmux));
|
||||||
|
|
||||||
|
pm.autoremove(st.pmux);
|
||||||
|
Cell *c = pm.module->addMux(NEW_ID, NE, EQ, st.eq->getPort(ID::Y), Y);
|
||||||
|
log(" -> %s (%s)\n", log_id(c), log_id(c->type));
|
||||||
|
}
|
||||||
|
|
||||||
#define GENERATE_PATTERN(pmclass, pattern) \
|
#define GENERATE_PATTERN(pmclass, pattern) \
|
||||||
generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design)
|
generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design)
|
||||||
|
|
||||||
|
@ -149,16 +167,17 @@ void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const
|
||||||
log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass);
|
log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass);
|
||||||
|
|
||||||
int modcnt = 0;
|
int modcnt = 0;
|
||||||
|
int maxmodcnt = 100;
|
||||||
int maxsubcnt = 4;
|
int maxsubcnt = 4;
|
||||||
int timeout = 0;
|
int timeout = 0;
|
||||||
vector<Module*> mods;
|
vector<Module*> mods;
|
||||||
|
|
||||||
while (modcnt < 100)
|
while (modcnt < maxmodcnt)
|
||||||
{
|
{
|
||||||
int submodcnt = 0, itercnt = 0, cellcnt = 0;
|
int submodcnt = 0, itercnt = 0, cellcnt = 0;
|
||||||
Module *mod = design->addModule(NEW_ID);
|
Module *mod = design->addModule(NEW_ID);
|
||||||
|
|
||||||
while (modcnt < 100 && submodcnt < maxsubcnt && itercnt++ < 1000)
|
while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000)
|
||||||
{
|
{
|
||||||
if (timeout++ > 10000)
|
if (timeout++ > 10000)
|
||||||
log_error("pmgen generator is stuck: 10000 iterations an no matching module generated.\n");
|
log_error("pmgen generator is stuck: 10000 iterations an no matching module generated.\n");
|
||||||
|
@ -232,6 +251,12 @@ struct TestPmgenPass : public Pass {
|
||||||
log("Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.\n");
|
log("Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
|
||||||
|
log("\n");
|
||||||
|
log(" test_pmgen -eqpmux [options] [selection]\n");
|
||||||
|
log("\n");
|
||||||
|
log("Demo for recursive pmgen patterns. Optimize EQ/NE/PMUX circuits.\n");
|
||||||
|
log("\n");
|
||||||
|
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" test_pmgen -generate [options] <pattern_name>\n");
|
log(" test_pmgen -generate [options] <pattern_name>\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -277,6 +302,25 @@ struct TestPmgenPass : public Pass {
|
||||||
test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_tree);
|
test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void execute_eqpmux(std::vector<std::string> args, RTLIL::Design *design)
|
||||||
|
{
|
||||||
|
log_header(design, "Executing TEST_PMGEN pass (-eqpmux).\n");
|
||||||
|
|
||||||
|
size_t argidx;
|
||||||
|
for (argidx = 2; argidx < args.size(); argidx++)
|
||||||
|
{
|
||||||
|
// if (args[argidx] == "-singleton") {
|
||||||
|
// singleton_mode = true;
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
|
for (auto module : design->selected_modules())
|
||||||
|
test_pmgen_pm(module, module->selected_cells()).run_eqpmux(opt_eqpmux);
|
||||||
|
}
|
||||||
|
|
||||||
void execute_generate(std::vector<std::string> args, RTLIL::Design *design)
|
void execute_generate(std::vector<std::string> args, RTLIL::Design *design)
|
||||||
{
|
{
|
||||||
log_header(design, "Executing TEST_PMGEN pass (-generate).\n");
|
log_header(design, "Executing TEST_PMGEN pass (-generate).\n");
|
||||||
|
@ -299,6 +343,9 @@ struct TestPmgenPass : public Pass {
|
||||||
if (pattern == "reduce")
|
if (pattern == "reduce")
|
||||||
return GENERATE_PATTERN(test_pmgen_pm, reduce);
|
return GENERATE_PATTERN(test_pmgen_pm, reduce);
|
||||||
|
|
||||||
|
if (pattern == "eqpmux")
|
||||||
|
return GENERATE_PATTERN(test_pmgen_pm, eqpmux);
|
||||||
|
|
||||||
if (pattern == "ice40_dsp")
|
if (pattern == "ice40_dsp")
|
||||||
return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp);
|
return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp);
|
||||||
|
|
||||||
|
@ -319,6 +366,8 @@ struct TestPmgenPass : public Pass {
|
||||||
return execute_reduce_chain(args, design);
|
return execute_reduce_chain(args, design);
|
||||||
if (args[1] == "-reduce_tree")
|
if (args[1] == "-reduce_tree")
|
||||||
return execute_reduce_tree(args, design);
|
return execute_reduce_tree(args, design);
|
||||||
|
if (args[1] == "-eqpmux")
|
||||||
|
return execute_eqpmux(args, design);
|
||||||
if (args[1] == "-generate")
|
if (args[1] == "-generate")
|
||||||
return execute_generate(args, design);
|
return execute_generate(args, design);
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,8 +60,8 @@ code portname
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
match next
|
match next
|
||||||
select nusers(port(next, \Y)) == 2
|
|
||||||
select next->type.in($_AND_, $_OR_, $_XOR_)
|
select next->type.in($_AND_, $_OR_, $_XOR_)
|
||||||
|
select nusers(port(next, \Y)) == 2
|
||||||
index <IdString> next->type === first->type
|
index <IdString> next->type === first->type
|
||||||
index <SigSpec> port(next, \Y) === port(first, portname)
|
index <SigSpec> port(next, \Y) === port(first, portname)
|
||||||
endmatch
|
endmatch
|
||||||
|
@ -77,8 +77,8 @@ arg first
|
||||||
|
|
||||||
match next
|
match next
|
||||||
semioptional
|
semioptional
|
||||||
select nusers(port(next, \Y)) == 2
|
|
||||||
select next->type.in($_AND_, $_OR_, $_XOR_)
|
select next->type.in($_AND_, $_OR_, $_XOR_)
|
||||||
|
select nusers(port(next, \Y)) == 2
|
||||||
index <IdString> next->type === chain.back().first->type
|
index <IdString> next->type === chain.back().first->type
|
||||||
index <SigSpec> port(next, \Y) === port(chain.back().first, chain.back().second)
|
index <SigSpec> port(next, \Y) === port(chain.back().first, chain.back().second)
|
||||||
generate 10
|
generate 10
|
||||||
|
@ -104,3 +104,86 @@ finally
|
||||||
if (next)
|
if (next)
|
||||||
chain.pop_back();
|
chain.pop_back();
|
||||||
endcode
|
endcode
|
||||||
|
|
||||||
|
// ==================================================================
|
||||||
|
|
||||||
|
pattern eqpmux
|
||||||
|
|
||||||
|
state <bool> eq_ne_signed
|
||||||
|
state <SigSpec> eq_inA eq_inB
|
||||||
|
state <int> pmux_slice_eq pmux_slice_ne
|
||||||
|
|
||||||
|
match eq
|
||||||
|
select eq->type == $eq
|
||||||
|
choice <IdString> AB {\A, \B}
|
||||||
|
define <IdString> BA AB == \A ? \B : \A
|
||||||
|
set eq_inA port(eq, \A)
|
||||||
|
set eq_inB port(eq, \B)
|
||||||
|
set eq_ne_signed param(eq, \A_SIGNED).as_bool()
|
||||||
|
generate 100 10
|
||||||
|
SigSpec A = module->addWire(NEW_ID, rng(7)+1);
|
||||||
|
SigSpec B = module->addWire(NEW_ID, rng(7)+1);
|
||||||
|
SigSpec Y = module->addWire(NEW_ID);
|
||||||
|
module->addEq(NEW_ID, A, B, Y, rng(2));
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
match pmux
|
||||||
|
select pmux->type == $pmux
|
||||||
|
slice idx GetSize(port(pmux, \S))
|
||||||
|
index <SigBit> port(pmux, \S)[idx] === port(eq, \Y)
|
||||||
|
set pmux_slice_eq idx
|
||||||
|
generate 100 10
|
||||||
|
int width = rng(7) + 1;
|
||||||
|
int numsel = rng(4) + 1;
|
||||||
|
int idx = rng(numsel);
|
||||||
|
|
||||||
|
SigSpec A = module->addWire(NEW_ID, width);
|
||||||
|
SigSpec Y = module->addWire(NEW_ID, width);
|
||||||
|
|
||||||
|
SigSpec B, S;
|
||||||
|
for (int i = 0; i < numsel; i++) {
|
||||||
|
B.append(module->addWire(NEW_ID, width));
|
||||||
|
S.append(i == idx ? port(eq, \Y) : module->addWire(NEW_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
module->addPmux(NEW_ID, A, B, S, Y);
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
match ne
|
||||||
|
select ne->type == $ne
|
||||||
|
choice <IdString> AB {\A, \B}
|
||||||
|
define <IdString> BA (AB == \A ? \B : \A)
|
||||||
|
index <SigSpec> port(ne, AB) === eq_inA
|
||||||
|
index <SigSpec> port(ne, BA) === eq_inB
|
||||||
|
index <int> param(ne, \A_SIGNED).as_bool() === eq_ne_signed
|
||||||
|
generate 100 10
|
||||||
|
SigSpec A = eq_inA, B = eq_inB, Y;
|
||||||
|
if (rng(2)) {
|
||||||
|
std::swap(A, B);
|
||||||
|
}
|
||||||
|
if (rng(2)) {
|
||||||
|
for (auto bit : port(pmux, \S)) {
|
||||||
|
if (nusers(bit) < 2)
|
||||||
|
Y.append(bit);
|
||||||
|
}
|
||||||
|
if (GetSize(Y))
|
||||||
|
Y = Y[rng(GetSize(Y))];
|
||||||
|
else
|
||||||
|
Y = module->addWire(NEW_ID);
|
||||||
|
} else {
|
||||||
|
Y = module->addWire(NEW_ID);
|
||||||
|
}
|
||||||
|
module->addNe(NEW_ID, A, B, Y, rng(2));
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
match pmux2
|
||||||
|
select pmux2->type == $pmux
|
||||||
|
slice idx GetSize(port(pmux2, \S))
|
||||||
|
index <Cell*> pmux2 === pmux
|
||||||
|
index <SigBit> port(pmux2, \S)[idx] === port(ne, \Y)
|
||||||
|
set pmux_slice_ne idx
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code
|
||||||
|
accept;
|
||||||
|
endcode
|
||||||
|
|
|
@ -117,6 +117,7 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
|
|
||||||
std::string top_opt, edif_file, blif_file, family;
|
std::string top_opt, edif_file, blif_file, family;
|
||||||
bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, abc9;
|
bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, abc9;
|
||||||
|
bool flatten_before_abc;
|
||||||
int widemux;
|
int widemux;
|
||||||
|
|
||||||
void clear_flags() YS_OVERRIDE
|
void clear_flags() YS_OVERRIDE
|
||||||
|
@ -139,6 +140,7 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
nocarry = false;
|
nocarry = false;
|
||||||
nowidelut = false;
|
nowidelut = false;
|
||||||
abc9 = false;
|
abc9 = false;
|
||||||
|
flatten_before_abc = false;
|
||||||
widemux = 0;
|
widemux = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,6 +180,10 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
flatten = true;
|
flatten = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-flatten_before_abc") {
|
||||||
|
flatten_before_abc = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (args[argidx] == "-retime") {
|
if (args[argidx] == "-retime") {
|
||||||
retime = true;
|
retime = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -417,6 +423,8 @@ struct SynthXilinxPass : public ScriptPass
|
||||||
|
|
||||||
if (check_label("map_luts")) {
|
if (check_label("map_luts")) {
|
||||||
run("opt_expr -mux_undef");
|
run("opt_expr -mux_undef");
|
||||||
|
if (flatten_before_abc)
|
||||||
|
run("flatten");
|
||||||
if (help_mode)
|
if (help_mode)
|
||||||
run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(option for 'nowidelut', option for '-retime')");
|
run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(option for 'nowidelut', option for '-retime')");
|
||||||
else if (abc9) {
|
else if (abc9) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue