From ad69c668cedaab76f84c982411d7cddbd868cccf Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 11 Jan 2019 14:02:16 +0100 Subject: [PATCH 01/53] Add mockup .pmg (pattern matcher generator) file Signed-off-by: Clifford Wolf --- passes/pmgen/ice40_dsp.pmg | 75 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 passes/pmgen/ice40_dsp.pmg diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg new file mode 100644 index 000000000..5a0af3e04 --- /dev/null +++ b/passes/pmgen/ice40_dsp.pmg @@ -0,0 +1,75 @@ +state SigBit clock +state bool clock_pol, clock_vld +state SigSpec sigA, sigB, sigY + +match mul + select mul->type.in($mul) + select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10 + select GetSize(mul->getPort(\Y)) > 10 +endmatch + +match ffA + select ffA->type.in($dff) + filter port(ffA, \Q) === port(mul, \A) + optional +endmatch + +code sigA clock clock_pol clock_vld + sigA = port(mul, \A); + + if (ffA != nullptr) { + sigA = port(ffA, \D); + + clock = port(ffA, \CLK).as_bit(); + clock_pol = param(ffA, \CLK_POLARITY).as_bool(); + clock_vld = true; + } +endcode + +match ffB + select ffB->type.in($dff) + filter port(ffB, \Q) === port(mul, \B) + optional +endmatch + +code sigB clock clok_pol clock_vld + sigB = port(mul, \B); + + if (ffB != nullptr) { + sigB = port(ffB, \D); + SigBit c = port(ffB, \CLK).as_bit(); + bool cp = param(ffB, \CLK_POLARITY).as_bool(); + + if (clock_vld && (c != clock || cp != clock_pol)) + reject; + + clock = c; + clock_pol = cp; + clock_vld = true; + } +endcode + +match ffY + select ffY->type.in($dff) + filter port(ffY, \D) === port(mul, \Y) + optional +endmatch + +code sigY clock clok_pol clock_vld + sigY = port(mul, \Y); + + if (ffY != nullptr) { + sigY = port(ffY, \D); + SigBit c = port(ffY, \CLK).as_bit(); + bool cp = param(ffY, \CLK_POLARITY).as_bool(); + + if (clock_vld && (c != clock || cp != clock_pol)) + reject; + + clock = c; + clock_pol = cp; + clock_vld = true; + } + + accept; +endcode From b9545aa0e1260f3d7123ec63e9dcfb0e022e2ff3 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 13 Jan 2019 10:57:11 +0100 Subject: [PATCH 02/53] Progress in pmgen Signed-off-by: Clifford Wolf --- passes/pmgen/.gitignore | 1 + passes/pmgen/Makefile.inc | 8 ++ passes/pmgen/ice40_dsp.cc | 65 +++++++++ passes/pmgen/ice40_dsp.pmg | 19 +-- passes/pmgen/pmgen.py | 262 +++++++++++++++++++++++++++++++++++++ 5 files changed, 347 insertions(+), 8 deletions(-) create mode 100644 passes/pmgen/.gitignore create mode 100644 passes/pmgen/Makefile.inc create mode 100644 passes/pmgen/ice40_dsp.cc create mode 100644 passes/pmgen/pmgen.py diff --git a/passes/pmgen/.gitignore b/passes/pmgen/.gitignore new file mode 100644 index 000000000..c9263057e --- /dev/null +++ b/passes/pmgen/.gitignore @@ -0,0 +1 @@ +/ice40_dsp_pm.h diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc new file mode 100644 index 000000000..33baaca30 --- /dev/null +++ b/passes/pmgen/Makefile.inc @@ -0,0 +1,8 @@ +OBJS += passes/pmgen/ice40_dsp.o + +passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h +EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h +.SECONDARY: passes/pmgen/ice40_dsp_pm.h + +passes/pmgen/ice40_dsp_pm.h: passes/pmgen/ice40_dsp.pmg passes/pmgen/pmgen.py + $(P) cd passes/pmgen && python3 pmgen.py ice40_dsp diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc new file mode 100644 index 000000000..0498f31b7 --- /dev/null +++ b/passes/pmgen/ice40_dsp.cc @@ -0,0 +1,65 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" +#include "passes/pmgen/ice40_dsp_pm.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +void ice40_dsp_accept(ice40_dsp_pm * /* pm */) +{ +} + +struct Ice40DspPass : public Pass { + Ice40DspPass() : Pass("ice40_dsp", "iCE40: map multipliers") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" ice40_dsp [options] [selection]\n"); + log("\n"); + log("Map multipliers and iCE40 DSP resources.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ICE40_DSP pass (map multipliers).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + ice40_dsp_pm pm(module); + pm.run(ice40_dsp_accept); + } + } +} Ice40DspPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 5a0af3e04..2b9bb8783 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -1,6 +1,6 @@ -state SigBit clock -state bool clock_pol, clock_vld -state SigSpec sigA, sigB, sigY +state clock +state clock_pol clock_vld +state sigA sigB sigY match mul select mul->type.in($mul) @@ -10,7 +10,8 @@ endmatch match ffA select ffA->type.in($dff) - filter port(ffA, \Q) === port(mul, \A) + select nusers(port(ffA, \Q)) == 2 + filter port(ffA, \Q) === port(mul, \A) optional endmatch @@ -28,11 +29,12 @@ endcode match ffB select ffB->type.in($dff) - filter port(ffB, \Q) === port(mul, \B) + select nusers(port(ffA, \Q)) == 2 + filter port(ffB, \Q) === port(mul, \B) optional endmatch -code sigB clock clok_pol clock_vld +code sigB clock clock_pol clock_vld sigB = port(mul, \B); if (ffB != nullptr) { @@ -51,11 +53,12 @@ endcode match ffY select ffY->type.in($dff) - filter port(ffY, \D) === port(mul, \Y) + select nusers(port(ffY, \D)) == 2 + filter port(ffY, \D) === port(mul, \Y) optional endmatch -code sigY clock clok_pol clock_vld +code sigY clock clock_pol clock_vld sigY = port(mul, \Y); if (ffY != nullptr) { diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py new file mode 100644 index 000000000..bf70a6dbd --- /dev/null +++ b/passes/pmgen/pmgen.py @@ -0,0 +1,262 @@ +#!/usr/bin/env python3 + +import re +import sys +import pprint + +pp = pprint.PrettyPrinter(indent=4) + +prefix = sys.argv[1] + +state_types = dict() +blocks = list() +ids = dict() + +def rewrite_cpp(s): + t = list() + i = 0 + while i < len(s): + if s[i] in ("'", '"') and i + 1 < len(s): + j = i + 1 + while j + 1 < len(s) and s[j] != s[i]: + if s[j] == '\\' and j + 1 < len(s): + j += 1 + j += 1 + t.append(s[i:j+1]) + i = j + 1 + continue + + if s[i] in ('$', '\\') and i + 1 < len(s): + j = i + 1 + while True: + if j == len(s): + j -= 1 + break + if ord('a') <= ord(s[j]) <= ord('z'): + j += 1 + continue + if ord('A') <= ord(s[j]) <= ord('Z'): + j += 1 + continue + if ord('0') <= ord(s[j]) <= ord('9'): + j += 1 + continue + if s[j] == '_': + j += 1 + continue + j -= 1 + break + + n = s[i:j+1] + i = j + 1 + + if n[0] == '$': + v = "id_d_" + n[1:] + else: + v = "id_b_" + n[1:] + + if v not in ids: + ids[v] = n + else: + assert ids[v] == n + + t.append(v) + continue + + if s[i] == "\t": + t.append(" ") + else: + t.append(s[i]) + + i += 1 + + return "".join(t) + +with open("%s.pmg" % prefix, "r") as f: + while True: + line = f.readline() + if line == "": break + line = line.strip() + + cmd = line.split() + if len(cmd) == 0: continue + cmd = cmd[0] + + if cmd == "state": + m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) + assert m + type_str = m.group(1) + states_str = m.group(2) + for s in re.split(r"\s+", states_str): + assert s not in state_types + state_types[s] = type_str + continue + + if cmd == "match": + block = dict() + block["type"] = "match" + + line = line.split() + assert len(line) == 2 + assert line[1] not in state_types + block["cell"] = line[1] + state_types[line[1]] = "Cell*"; + + block["select"] = list() + block["filter"] = list() + block["optional"] = False + + while True: + l = f.readline() + assert l != "" + a = l.split() + if len(a) == 0: continue + if a[0] == "endmatch": break + + if a[0] == "select": + b = l.lstrip()[6:] + block["select"].append(rewrite_cpp(b.strip())) + continue + + if a[0] == "filter": + m = re.match(r"^\s*filter\s+<(.*?)>\s+(.*?)\s*===\s*(.*?)\s*$", l) + assert m + block["filter"].append((m.group(1), rewrite_cpp(m.group(2)), rewrite_cpp(m.group(3)))) + continue + + if a[0] == "optional": + block["optional"] = True + continue + + assert False + + blocks.append(block) + + if cmd == "code": + block = dict() + block["type"] = "code" + block["code"] = list() + block["states"] = set() + + for s in line.split()[1:]: + assert s in state_types + block["states"].add(s) + + while True: + l = f.readline() + assert l != "" + a = l.split() + if len(a) == 0: continue + if a[0] == "endcode": break + + block["code"].append(rewrite_cpp(l.rstrip())) + + blocks.append(block) + +# pp.pprint(blocks) + +with open("%s_pm.h" % prefix, "w") as f: + print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f) + print("#include \"kernel/yosys.h\"", file=f) + print("#include \"kernel/sigtools.h\"", file=f) + print("YOSYS_NAMESPACE_BEGIN", file=f) + print("struct {}_pm {{".format(prefix), file=f) + print(" Module *module;", file=f) + print(" SigMap sigmap;", file=f) + print(" std::function on_accept;".format(prefix), file=f) + print("", file=f) + + for index in range(len(blocks)): + block = blocks[index] + if block["type"] == "match": + index_types = list() + for filt in block["filter"]: + index_types.append(filt[0]) + print(" typedef std::tuple<{}> index_{}_key_type;".format(", ".join(index_types), index), file=f) + print(" dict> index_{};".format(index, index), file=f) + print(" pool blacklist;", file=f) + print("", file=f) + + print(" struct state_t {", file=f) + + for s, t in sorted(state_types.items()): + print(" {} {};".format(t, s), file=f) + print(" } st;", file=f) + print("", file=f) + + for v, n in sorted(ids.items()): + if n[0] == "\\": + print(" IdString {}{{\"\\{}\"}};".format(v, n), file=f) + else: + print(" IdString {}{{\"{}\"}};".format(v, n), file=f) + print("", file=f) + + print(" {}_pm(Module *module) :".format(prefix), file=f) + print(" module(module), sigmap(module) {", file=f) + print(" }", file=f) + + print("", file=f) + print(" void run(std::function on_accept_f) {{".format(prefix), file=f) + print(" on_accept = on_accept_f;", file=f) + if len(blocks): + print(" block_0();", file=f) + print(" }", file=f) + + for index in range(len(blocks)): + block = blocks[index] + + print("", file=f) + print(" void block_{}() {{".format(index), file=f) + + const_st = set() + nonconst_st = set() + restore_st = set() + + for i in range(index): + if blocks[i]["type"] == "code": + for s in blocks[i]["states"]: + const_st.add(s) + elif blocks[i]["type"] == "match": + const_st.add(blocks[i]["cell"]) + else: + assert False + + if block["type"] == "code": + for s in block["states"]: + if s in const_st: + const_st.remove(s) + restore_st.add(s) + nonconst_st.add(s) + elif block["type"] == "match": + s = block["cell"] + assert s not in const_st + nonconst_st.add(s) + else: + assert False + + for s in sorted(const_st): + t = state_types[s] + if t.endswith("*"): + print(" {} const &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) + else: + print(" const {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) + + for s in sorted(nonconst_st): + t = state_types[s] + print(" {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) + + if len(restore_st): + print("", file=f) + for s in sorted(restore_st): + t = state_types[s] + print(" {} backup_{} = st.{};".format(t, s, s), file=f) + + if len(restore_st): + print("", file=f) + for s in sorted(restore_st): + t = state_types[s] + print(" st.{} = backup_{};".format(s, s), file=f) + + print(" }", file=f) + + print("};\nYOSYS_NAMESPACE_END", file=f) From 1f8e76f993b602bb8b03af216615a248bbde3652 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 13 Jan 2019 12:53:13 +0100 Subject: [PATCH 03/53] Progress in pmgen Signed-off-by: Clifford Wolf --- passes/pmgen/ice40_dsp.cc | 11 ++- passes/pmgen/ice40_dsp.pmg | 6 +- passes/pmgen/pmgen.py | 163 +++++++++++++++++++++++++++++++++---- 3 files changed, 158 insertions(+), 22 deletions(-) diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 0498f31b7..049ef6c0e 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -24,8 +24,15 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -void ice40_dsp_accept(ice40_dsp_pm * /* pm */) +void ice40_dsp_accept(ice40_dsp_pm *pm) { + log("\n"); + log("mul: %s\n", pm->st.mul ? log_id(pm->st.mul) : "--"); + log("ffA: %s\n", pm->st.ffA ? log_id(pm->st.ffA) : "--"); + log("ffB: %s\n", pm->st.ffB ? log_id(pm->st.ffB) : "--"); + log("ffY: %s\n", pm->st.ffY ? log_id(pm->st.ffY) : "--"); + + pm->blacklist(pm->st.mul); } struct Ice40DspPass : public Pass { @@ -56,7 +63,7 @@ struct Ice40DspPass : public Pass { for (auto module : design->selected_modules()) { - ice40_dsp_pm pm(module); + ice40_dsp_pm pm(module, module->cells()); pm.run(ice40_dsp_accept); } } diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 2b9bb8783..a2937ddc6 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -10,7 +10,7 @@ endmatch match ffA select ffA->type.in($dff) - select nusers(port(ffA, \Q)) == 2 + // select nusers(port(ffA, \Q)) == 2 filter port(ffA, \Q) === port(mul, \A) optional endmatch @@ -29,7 +29,7 @@ endcode match ffB select ffB->type.in($dff) - select nusers(port(ffA, \Q)) == 2 + // select nusers(port(ffB, \Q)) == 2 filter port(ffB, \Q) === port(mul, \B) optional endmatch @@ -73,6 +73,4 @@ code sigY clock clock_pol clock_vld clock_pol = cp; clock_vld = true; } - - accept; endcode diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index bf70a6dbd..7d33c4fc9 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -79,7 +79,7 @@ with open("%s.pmg" % prefix, "r") as f: line = line.strip() cmd = line.split() - if len(cmd) == 0: continue + if len(cmd) == 0 or cmd[0].startswith("//"): continue cmd = cmd[0] if cmd == "state": @@ -110,7 +110,7 @@ with open("%s.pmg" % prefix, "r") as f: l = f.readline() assert l != "" a = l.split() - if len(a) == 0: continue + if len(a) == 0 or a[0].startswith("//"): continue if a[0] == "endmatch": break if a[0] == "select": @@ -153,13 +153,17 @@ with open("%s.pmg" % prefix, "r") as f: blocks.append(block) -# pp.pprint(blocks) - with open("%s_pm.h" % prefix, "w") as f: print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f) + print("", file=f) + print("#include \"kernel/yosys.h\"", file=f) print("#include \"kernel/sigtools.h\"", file=f) + print("", file=f) + print("YOSYS_NAMESPACE_BEGIN", file=f) + print("", file=f) + print("struct {}_pm {{".format(prefix), file=f) print(" Module *module;", file=f) print(" SigMap sigmap;", file=f) @@ -174,7 +178,9 @@ with open("%s_pm.h" % prefix, "w") as f: index_types.append(filt[0]) print(" typedef std::tuple<{}> index_{}_key_type;".format(", ".join(index_types), index), file=f) print(" dict> index_{};".format(index, index), file=f) - print(" pool blacklist;", file=f) + print(" dict> sigusers;", file=f) + print(" pool blacklist_cells;", file=f) + print(" int rollback;", file=f) print("", file=f) print(" struct state_t {", file=f) @@ -191,21 +197,89 @@ with open("%s_pm.h" % prefix, "w") as f: print(" IdString {}{{\"{}\"}};".format(v, n), file=f) print("", file=f) - print(" {}_pm(Module *module) :".format(prefix), file=f) - print(" module(module), sigmap(module) {", file=f) + print(" void add_siguser(const SigSpec &sig, Cell *cell) {", file=f) + print(" for (auto bit : sigmap(sig)) {", 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(" }", file=f) print(" }", file=f) - print("", file=f) + + print(" void blacklist(Cell *cell) {", file=f) + print(" blacklist_cells.insert(cell);", file=f) + print(" }", file=f) + print("", file=f) + + print(" void check_blacklist() {", file=f) + for index in range(len(blocks)): + block = blocks[index] + if block["type"] == "match": + print(" if (st.{} != nullptr && blacklist_cells.count(st.{})) {{".format(block["cell"], block["cell"]), file=f) + print(" rollback = {};".format(index+1), file=f) + print(" return;", file=f) + print(" }", file=f) + print(" rollback = 0;", file=f) + print(" }", file=f) + print("", file=f) + + print(" SigSpec port(Cell *cell, IdString portname) {", file=f) + print(" return sigmap(cell->getPort(portname));", file=f) + print(" }", file=f) + print("", file=f) + + print(" Const param(Cell *cell, IdString paramname) {", file=f) + print(" return cell->getParam(paramname);", file=f) + print(" }", file=f) + print("", file=f) + + print(" int nusers(const SigSpec &sig) {", file=f) + print(" pool users;", file=f) + print(" for (auto bit : sigmap(sig))", file=f) + print(" for (auto user : sigusers[bit])", file=f) + print(" users.insert(user);", file=f) + print(" return GetSize(users);", file=f) + print(" }", file=f) + print("", file=f) + + print(" {}_pm(Module *module, const vector &cells) :".format(prefix), file=f) + print(" module(module), sigmap(module) {", file=f) + print(" for (auto cell : cells) {", file=f) + print(" for (auto &conn : cell->connections())", file=f) + print(" add_siguser(conn.second, cell);", file=f) + + for index in range(len(blocks)): + block = blocks[index] + if block["type"] == "match": + print(" do {", file=f) + print(" Cell *{} = cell;".format(block["cell"]), file=f) + for expr in block["select"]: + print(" if (!({})) break;".format(expr), file=f) + print(" index_{}_key_type key;".format(index), file=f) + for field, filt in enumerate(block["filter"]): + print(" std::get<{}>(key) = {};".format(field, filt[1]), file=f) + print(" index_{}[key].push_back(cell);".format(index), file=f) + print(" } while (0);", file=f) + + print(" }", file=f) + print(" }", file=f) + print("", file=f) + print(" void run(std::function on_accept_f) {{".format(prefix), file=f) print(" on_accept = on_accept_f;", file=f) - if len(blocks): - print(" block_0();", file=f) + print(" rollback = 0;", file=f) + print(" block_0();", file=f) print(" }", file=f) + print("", file=f) + + print("#define reject break", file=f) + print("#define accept do { on_accept(this); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f) + print("", file=f) for index in range(len(blocks)): block = blocks[index] - print("", file=f) print(" void block_{}() {{".format(index), file=f) const_st = set() @@ -251,12 +325,69 @@ with open("%s_pm.h" % prefix, "w") as f: t = state_types[s] print(" {} backup_{} = st.{};".format(t, s, s), file=f) - if len(restore_st): + if block["type"] == "code": print("", file=f) - for s in sorted(restore_st): - t = state_types[s] - print(" st.{} = backup_{};".format(s, s), file=f) + print(" do {", file=f) + for line in block["code"]: + print(" " + line, file=f) + + print("", file=f) + print(" block_{}();".format(index+1), file=f) + print("rollback_label: YS_ATTRIBUTE(unused);", file=f) + print(" } while (0);", file=f) + + if len(restore_st): + print("", file=f) + for s in sorted(restore_st): + t = state_types[s] + print(" st.{} = backup_{};".format(s, s), file=f) + + elif block["type"] == "match": + assert len(restore_st) == 0 + + print("", file=f) + print(" index_{}_key_type key;".format(index), file=f) + for field, filt in enumerate(block["filter"]): + print(" std::get<{}>(key) = {};".format(field, filt[2]), file=f) + print(" const vector &cells = index_{}[key];".format(index), file=f) + + print("", file=f) + print(" for (int idx = 0; idx < GetSize(cells); idx++) {", file=f) + print(" {} = cells[idx];".format(block["cell"]), file=f) + print(" block_{}();".format(index+1), file=f) + print(" if (rollback) {", file=f) + print(" if (rollback != {}) {{".format(index+1), file=f) + print(" {} = nullptr;".format(block["cell"]), file=f) + print(" return;", file=f) + print(" }", file=f) + print(" rollback = 0;", file=f) + print(" }", file=f) + print(" }", file=f) + + print("", file=f) + print(" {} = nullptr;".format(block["cell"]), file=f) + + if block["optional"]: + print(" block_{}();".format(index+1), file=f) + + else: + assert False + print(" }", file=f) + print("", file=f) - print("};\nYOSYS_NAMESPACE_END", file=f) + print("#undef reject", file=f) + print("#undef accept", file=f) + print("", file=f) + + print(" void block_{}() {{".format(len(blocks)), file=f) + print(" on_accept(this);", file=f) + print(" check_blacklist();", file=f) + print(" }", file=f) + print("};", file=f) + + print("", file=f) + print("YOSYS_NAMESPACE_END", file=f) + +# pp.pprint(blocks) From d45379936b82a26b713e40d92f3e73cf03bcf7cc Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 13 Jan 2019 17:03:58 +0100 Subject: [PATCH 04/53] Progress in pmgen Signed-off-by: Clifford Wolf --- passes/pmgen/ice40_dsp.cc | 29 ++++++++------- passes/pmgen/ice40_dsp.pmg | 74 ++++++++++++++++++++++++++++++++++---- passes/pmgen/pmgen.py | 72 ++++++++++++++++++++++++++++--------- 3 files changed, 139 insertions(+), 36 deletions(-) diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 049ef6c0e..a8f63ebfe 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -24,17 +24,6 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -void ice40_dsp_accept(ice40_dsp_pm *pm) -{ - log("\n"); - log("mul: %s\n", pm->st.mul ? log_id(pm->st.mul) : "--"); - log("ffA: %s\n", pm->st.ffA ? log_id(pm->st.ffA) : "--"); - log("ffB: %s\n", pm->st.ffB ? log_id(pm->st.ffB) : "--"); - log("ffY: %s\n", pm->st.ffY ? log_id(pm->st.ffY) : "--"); - - pm->blacklist(pm->st.mul); -} - struct Ice40DspPass : public Pass { Ice40DspPass() : Pass("ice40_dsp", "iCE40: map multipliers") { } void help() YS_OVERRIDE @@ -64,7 +53,23 @@ struct Ice40DspPass : public Pass { for (auto module : design->selected_modules()) { ice40_dsp_pm pm(module, module->cells()); - pm.run(ice40_dsp_accept); + pm.match([&]() + { + log("\n"); + log("ffA: %s\n", log_id(pm.st.ffA, "--")); + log("ffB: %s\n", log_id(pm.st.ffB, "--")); + log("mul: %s\n", log_id(pm.st.mul, "--")); + log("ffY: %s\n", log_id(pm.st.ffY, "--")); + log("addAB: %s\n", log_id(pm.st.addAB, "--")); + log("muxAB: %s\n", log_id(pm.st.muxAB, "--")); + log("ffS: %s\n", log_id(pm.st.ffS, "--")); + + pm.blacklist(pm.st.mul); + pm.blacklist(pm.st.ffA); + pm.blacklist(pm.st.ffB); + pm.blacklist(pm.st.ffY); + pm.blacklist(pm.st.ffS); + }); } } } Ice40DspPass; diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index a2937ddc6..1370cb66a 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -1,6 +1,7 @@ state clock state clock_pol clock_vld -state sigA sigB sigY +state sigA sigB sigY sigS +state addAB muxAB match mul select mul->type.in($mul) @@ -11,14 +12,14 @@ endmatch match ffA select ffA->type.in($dff) // select nusers(port(ffA, \Q)) == 2 - filter port(ffA, \Q) === port(mul, \A) + index port(ffA, \Q) === port(mul, \A) optional endmatch code sigA clock clock_pol clock_vld sigA = port(mul, \A); - if (ffA != nullptr) { + if (ffA) { sigA = port(ffA, \D); clock = port(ffA, \CLK).as_bit(); @@ -30,14 +31,14 @@ endcode match ffB select ffB->type.in($dff) // select nusers(port(ffB, \Q)) == 2 - filter port(ffB, \Q) === port(mul, \B) + index port(ffB, \Q) === port(mul, \B) optional endmatch code sigB clock clock_pol clock_vld sigB = port(mul, \B); - if (ffB != nullptr) { + if (ffB) { sigB = port(ffB, \D); SigBit c = port(ffB, \CLK).as_bit(); bool cp = param(ffB, \CLK_POLARITY).as_bool(); @@ -54,14 +55,14 @@ endcode match ffY select ffY->type.in($dff) select nusers(port(ffY, \D)) == 2 - filter port(ffY, \D) === port(mul, \Y) + index port(ffY, \D) === port(mul, \Y) optional endmatch code sigY clock clock_pol clock_vld sigY = port(mul, \Y); - if (ffY != nullptr) { + if (ffY) { sigY = port(ffY, \D); SigBit c = port(ffY, \CLK).as_bit(); bool cp = param(ffY, \CLK_POLARITY).as_bool(); @@ -74,3 +75,62 @@ code sigY clock clock_pol clock_vld clock_vld = true; } endcode + +match addA + select addA->type.in($add, $sub) + select nusers(port(addA, \A)) == 2 + index port(addA, \A) === sigY + optional +endmatch + +match addB + if !addA + select addB->type.in($add, $sub) + select nusers(port(addB, \B)) == 2 + index port(addB, \B) === sigY + optional +endmatch + +code addAB sigS + if (addA) { + addAB = addA; + sigS = port(addA, \B); + } + if (addB) { + addAB = addB; + sigS = port(addB, \A); + } +endcode + +match muxA + if addAB + select muxA->type.in($mux) + select nusers(port(muxA, \A)) == 2 + index port(muxA, \A) === port(addAB, \Y) + optional +endmatch + +match muxB + if addAB + if !muxA + select muxB->type.in($mux) + select nusers(port(muxB, \B)) == 2 + index port(muxB, \B) === port(addAB, \Y) + optional +endmatch + +code muxAB + muxAB = addAB; + if (muxA) + muxAB = muxA; + if (muxB) + muxAB = muxB; +endcode + +match ffS + if muxAB + select ffS->type.in($dff) + select nusers(port(ffS, \D)) == 2 + index port(ffS, \D) === port(muxAB, \Y) + index port(ffS, \Q) === sigS +endmatch diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 7d33c4fc9..88d60d298 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -102,7 +102,9 @@ with open("%s.pmg" % prefix, "r") as f: block["cell"] = line[1] state_types[line[1]] = "Cell*"; + block["if"] = list() block["select"] = list() + block["index"] = list() block["filter"] = list() block["optional"] = False @@ -113,15 +115,25 @@ with open("%s.pmg" % prefix, "r") as f: if len(a) == 0 or a[0].startswith("//"): continue if a[0] == "endmatch": break + if a[0] == "if": + b = l.lstrip()[2:] + block["if"].append(rewrite_cpp(b.strip())) + continue + if a[0] == "select": b = l.lstrip()[6:] block["select"].append(rewrite_cpp(b.strip())) continue - if a[0] == "filter": - m = re.match(r"^\s*filter\s+<(.*?)>\s+(.*?)\s*===\s*(.*?)\s*$", l) + if a[0] == "index": + m = re.match(r"^\s*index\s+<(.*?)>\s+(.*?)\s*===\s*(.*?)\s*$", l) assert m - block["filter"].append((m.group(1), rewrite_cpp(m.group(2)), rewrite_cpp(m.group(3)))) + block["index"].append((m.group(1), rewrite_cpp(m.group(2)), rewrite_cpp(m.group(3)))) + continue + + if a[0] == "filter": + b = l.lstrip()[6:] + block["filter"].append(rewrite_cpp(b.strip())) continue if a[0] == "optional": @@ -167,15 +179,15 @@ with open("%s_pm.h" % prefix, "w") as f: print("struct {}_pm {{".format(prefix), file=f) print(" Module *module;", file=f) print(" SigMap sigmap;", file=f) - print(" std::function on_accept;".format(prefix), file=f) + print(" std::function on_accept;".format(prefix), file=f) print("", file=f) for index in range(len(blocks)): block = blocks[index] if block["type"] == "match": index_types = list() - for filt in block["filter"]: - index_types.append(filt[0]) + for entry in block["index"]: + index_types.append(entry[0]) print(" typedef std::tuple<{}> index_{}_key_type;".format(", ".join(index_types), index), file=f) print(" dict> index_{};".format(index, index), file=f) print(" dict> sigusers;", file=f) @@ -208,7 +220,8 @@ with open("%s_pm.h" % prefix, "w") as f: print("", file=f) print(" void blacklist(Cell *cell) {", file=f) - print(" blacklist_cells.insert(cell);", file=f) + print(" if (cell != nullptr)", file=f) + print(" blacklist_cells.insert(cell);", file=f) print(" }", file=f) print("", file=f) @@ -248,6 +261,8 @@ with open("%s_pm.h" % prefix, "w") as f: print(" for (auto cell : cells) {", file=f) print(" for (auto &conn : cell->connections())", file=f) print(" add_siguser(conn.second, cell);", file=f) + print(" }", file=f) + print(" for (auto cell : cells) {", file=f) for index in range(len(blocks)): block = blocks[index] @@ -257,8 +272,8 @@ with open("%s_pm.h" % prefix, "w") as f: for expr in block["select"]: print(" if (!({})) break;".format(expr), file=f) print(" index_{}_key_type key;".format(index), file=f) - for field, filt in enumerate(block["filter"]): - print(" std::get<{}>(key) = {};".format(field, filt[1]), file=f) + for field, entry in enumerate(block["index"]): + print(" std::get<{}>(key) = {};".format(field, entry[1]), file=f) print(" index_{}[key].push_back(cell);".format(index), file=f) print(" } while (0);", file=f) @@ -266,15 +281,20 @@ with open("%s_pm.h" % prefix, "w") as f: print(" }", file=f) print("", file=f) - print(" void run(std::function on_accept_f) {{".format(prefix), file=f) + print(" void match(std::function on_accept_f) {{".format(prefix), file=f) print(" on_accept = on_accept_f;", file=f) print(" rollback = 0;", file=f) + for s, t in sorted(state_types.items()): + if t.endswith("*"): + print(" st.{} = nullptr;".format(s), file=f) + else: + print(" st.{} = {}();".format(s, t), file=f) print(" block_0();", file=f) print(" }", file=f) print("", file=f) print("#define reject break", file=f) - print("#define accept do { on_accept(this); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f) + print("#define accept do { on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f) print("", file=f) for index in range(len(blocks)): @@ -323,7 +343,7 @@ with open("%s_pm.h" % prefix, "w") as f: print("", file=f) for s in sorted(restore_st): t = state_types[s] - print(" {} backup_{} = st.{};".format(t, s, s), file=f) + print(" {} backup_{} = {};".format(t, s, s), file=f) if block["type"] == "code": print("", file=f) @@ -336,24 +356,42 @@ with open("%s_pm.h" % prefix, "w") as f: print("rollback_label: YS_ATTRIBUTE(unused);", file=f) print(" } while (0);", file=f) - if len(restore_st): + if len(restore_st) or len(nonconst_st): print("", file=f) for s in sorted(restore_st): t = state_types[s] - print(" st.{} = backup_{};".format(s, s), file=f) + print(" {} = backup_{};".format(s, s), file=f) + for s in sorted(nonconst_st): + if s not in restore_st: + t = state_types[s] + if t.endswith("*"): + print(" {} = nullptr;".format(s), file=f) + else: + print(" {} = {}();".format(s, t), file=f) elif block["type"] == "match": assert len(restore_st) == 0 + if len(block["if"]): + for expr in block["if"]: + print("", file=f) + print(" if (!({})) {{".format(expr), file=f) + print(" {} = nullptr;".format(block["cell"]), file=f) + print(" block_{}();".format(index+1), file=f) + print(" return;", file=f) + print(" }", file=f) + print("", file=f) print(" index_{}_key_type key;".format(index), file=f) - for field, filt in enumerate(block["filter"]): - print(" std::get<{}>(key) = {};".format(field, filt[2]), file=f) + for field, entry in enumerate(block["index"]): + print(" std::get<{}>(key) = {};".format(field, entry[2]), file=f) print(" const vector &cells = index_{}[key];".format(index), file=f) print("", file=f) print(" for (int idx = 0; idx < GetSize(cells); idx++) {", file=f) print(" {} = cells[idx];".format(block["cell"]), file=f) + for expr in block["filter"]: + print(" if (!({})) continue;".format(expr), file=f) print(" block_{}();".format(index+1), file=f) print(" if (rollback) {", file=f) print(" if (rollback != {}) {{".format(index+1), file=f) @@ -382,7 +420,7 @@ with open("%s_pm.h" % prefix, "w") as f: print("", file=f) print(" void block_{}() {{".format(len(blocks)), file=f) - print(" on_accept(this);", file=f) + print(" on_accept();", file=f) print(" check_blacklist();", file=f) print(" }", file=f) print("};", file=f) From 55ac03038270f4a70da5e579dd317487e20fe6cf Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 13 Jan 2019 17:15:40 +0100 Subject: [PATCH 05/53] Fix pmgen "reject" statement Signed-off-by: Clifford Wolf --- passes/pmgen/pmgen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 88d60d298..6486278d4 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -293,7 +293,7 @@ with open("%s_pm.h" % prefix, "w") as f: print(" }", file=f) print("", file=f) - print("#define reject break", file=f) + print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f) print("#define accept do { on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f) print("", file=f) From 5216735210f1b081f84c8ec110acb1cf9c3a0555 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 14 Jan 2019 13:29:27 +0100 Subject: [PATCH 06/53] Progress in pmgen, add pmgen README Signed-off-by: Clifford Wolf --- passes/pmgen/README.md | 224 ++++++++++++++++++++++++++++++++++++++ passes/pmgen/ice40_dsp.cc | 4 +- passes/pmgen/pmgen.py | 46 ++++++-- 3 files changed, 260 insertions(+), 14 deletions(-) create mode 100644 passes/pmgen/README.md diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md new file mode 100644 index 000000000..27e54b43e --- /dev/null +++ b/passes/pmgen/README.md @@ -0,0 +1,224 @@ +Pattern Matcher Generator +========================= + +The program `pmgen.py` reads a `.pmg` (Pattern Matcher Generator) file and +writes a header-only C++ library that implements that pattern matcher. + +The "patterns" in this context are subgraphs in a Yosys RTLIL netlist. + +The algorithm used in the generated pattern matcher is a simple recursive +search with backtracking. It is left to the author of the `.pmg` file to +determine an efficient cell order for the search that allows for maximum +use of indices and early backtracking. + + +API of Generated Matcher +======================== + +When `pmgen.py` reads a `foobar.pmg` file, it writes `foobar_pm.h` containing +a class `foobar_pm`. That class is instanciated with an RTLIL module and a +list of cells from that module: + + foobar_pm pm(module, module->selected_cells()); + +The caller must make sure that none of the cells in the 2nd argument are +deleted for as long as the patter matcher instance is used. + +At any time it is possible to disable cells, preventing them from showing +up in any future matches: + + pm.blacklist(some_cell); + +The `.run(callback_function)` method searches for all matches and calls the +callback function for each found match: + + pm.run([&](){ + log("found matching 'foo' cell: %s\n", log_id(pm.st.foo)); + log(" with 'bar' cell: %s\n", log_id(pm.st.bar)); + }); + +The `.pmg` file declares matcher state variables that are accessible via the +`.st.` members. (The `.st` member is of type `foobar_pm::state_t`.) + +Similarly the `.pmg` file declares user data variables that become members of +`.ud`, a struct of type `foobar_pm::udata_t`. + + +The .pmg File Format +==================== + +The `.pmg` file format is a simple line-based file format. For the most part +lines consist of whitespace-separated tokens. + +Lines in `.pmg` files starting with `//` are comments. + +Declaring state variables +------------------------- + +One or more state variables can be declared using the `state` statement, +followed by a C++ type in angle brackets, followed by a whitespace separated +list of variable names. For example: + + state flag1 flag2 happy big + state sigA sigB sigY + +State variables are automatically managed by the generated backtracking algorithm +and saved and restored as needed. + +They are atomatically initialzed to the default constructed value of their type +when `.run(callback_function)` is called. + +Declaring udata variables +------------------------- + +Udata (user-data) variables can be used for example to configure the matcher or +the callback function used to perform actions on found matches. + +There is no automatic management of udata variables. For this reason it is +recommended that the user-supplied matcher code treats them as read-only +variables. + +They are declared like state variables, just using the `udata` statement: + + udata min_data_width max_data_width + udata data_port_name + +They are atomatically initialzed to the default constructed value of their type +when ther pattern matcher object is constructed. + +Embedded C++ code +----------------- + +Many statements in a `.pmg` file contain C++ code. However, there are some +slight additions to regular C++/Yosys/RTLIL code that make it a bit easier to +write matchers: + +- Identifiers starting with a dollar sign or backslash are automatically + converted to special IdString variables that are initialized when the + matcher object is constructed. + +- The `port(, )` function is a handy alias for + `sigmap(->getPort())`. + +- Similarly `param(, )` looks up a parameter on a cell. + +- The function `nusers()` returns the number of different cells + connected to any of the given signal bits, plus one if any of the signal + bits is also a primary input or primary output. + +- In `code..endcode` blocks there exist `accept`, `reject`, and `branch` + statements. + +- In `index` statements there is a special `===` operator for the index + lookup. + +Matching cells +-------------- + +Cells are matched using `match..endmatch` blocks. For example: + + match mul + if ff + select mul->type == $mul + select nusers(port(mul, \Y) == 2 + index port(mul, \Y) === port(ff, \D) + filter some_weird_function(mul) < other_weird_function(ff) + optional + endmatch + +A `match` block starts with `match ` and implicitly generates +a state variable `` of type `RTLIL::Cell*`. + +All statements in the match block are optional. (An empty match block +would simply match each and every cell in the module.) + +The `if ` statement makes the match block conditional. If +`` evaluates to `false` then the match block will be ignored +and the corresponding state variable is set to `nullptr`. In our example +we only try to match the `mul` cell if the `ff` state variable points +to a cell. (Presumably `ff` is provided by a prior `match` block.) + +The `select` lines are evaluated once for each cell when the matcher is +initialized. A `match` block will only consider cells for which all `select` +expressions evaluated to `true`. Note that the state variable corresponding to +the match (in the example `mul`) is the only state variable that may be used +`select` lines. + +Index lines are using the `index expr1 === expr2` syntax. `expr1` is +evaluated during matcher initialization and the same restrictions apply as for +`select` expressions. `expr2` is evaluated when the match is calulated. It is a +function of any state variables assigned to by previous blocks. Both expression +are converted to the given type and compared for equality. Only cells for which +all `index` statements in the block pass are considered by the match. + +Note that `select` and `index` are fast operations. Thus `select` and `index` +should be used whenever possible to create efficient matchers. + +Finally, `filter ` narrows down the remaining list of cells. For +performance reasons `filter` statements should only be used for things that +can't be done using `select` and `index`. + +The `optional` statement marks optional matches. I.e. the matcher will also +explore the case where `mul` is set to `nullptr`. Without the `optional` +statement a match may only be assigned nullptr when one of the `if` expressions +evaluates to `false`. + +Additional code +--------------- + +Interleaved with `match..endmatch` blocks there may be `code..endcode` blocks. +Such a block starts with the keyword `code` followed by a list of state variables +that the block may modify. For example: + + code addAB sigS + if (addA) { + addAB = addA; + sigS = port(addA, \B); + } + if (addB) { + addAB = addB; + sigS = port(addB, \A); + } + endcode + +The special keyword `reject` can be used to reject the current state and +backtrack. For example: + + code + if (ffA && ffB) { + if (port(ffA, \CLK) != port(ffB, \CLK)) + reject; + if (param(ffA, \CLK_POLARITY) != param(ffB, \CLK_POLARITY)) + reject; + } + endcode + +Similarly, the special keyword `accept` can be used to accept the current +state. (`accept` will not backtrack. This means it continues with the current +branch and may accept a larger match later.) + +The special keyword `branch` can be used to explore different cases. Note that +each code block has an implicit `branch` at the end. So most use-cases of the +`branch` keyword need to end the block with `reject` to avoid the implicit +branch at the end. For example: + + state mode + + code mode + for (mode = 0; mode < 8; mode++) + branch; + reject; + endcode + +But in some cases it is more natural to utilize the implicit branch statement: + + state portAB + + code portAB + portAB = \A; + branch; + portAB = \B; + endcode + +There is an implicit `code..endcode` block at the end of each `.pgm` file +that just accepts everything that gets all the way there. diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index a8f63ebfe..78b5bad33 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -52,8 +52,8 @@ struct Ice40DspPass : public Pass { for (auto module : design->selected_modules()) { - ice40_dsp_pm pm(module, module->cells()); - pm.match([&]() + ice40_dsp_pm pm(module, module->selected_cells()); + pm.run([&]() { log("\n"); log("ffA: %s\n", log_id(pm.st.ffA, "--")); diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 6486278d4..885f6db1c 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -9,6 +9,7 @@ pp = pprint.PrettyPrinter(indent=4) prefix = sys.argv[1] state_types = dict() +udata_types = dict() blocks = list() ids = dict() @@ -92,6 +93,16 @@ with open("%s.pmg" % prefix, "r") as f: state_types[s] = type_str continue + if cmd == "udata": + m = re.match(r"^udata\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) + assert m + type_str = m.group(1) + udatas_str = m.group(2) + for s in re.split(r"\s+", udatas_str): + assert s not in udata_types + udata_types[s] = type_str + continue + if cmd == "match": block = dict() block["type"] = "match" @@ -196,12 +207,17 @@ with open("%s_pm.h" % prefix, "w") as f: print("", file=f) print(" struct state_t {", file=f) - for s, t in sorted(state_types.items()): print(" {} {};".format(t, s), file=f) print(" } st;", file=f) print("", file=f) + print(" struct udata_t {", file=f) + for s, t in sorted(udata_types.items()): + print(" {} {};".format(t, s), file=f) + print(" } ud;", file=f) + print("", file=f) + for v, n in sorted(ids.items()): if n[0] == "\\": print(" IdString {}{{\"\\{}\"}};".format(v, n), file=f) @@ -258,7 +274,12 @@ with open("%s_pm.h" % prefix, "w") as f: print(" {}_pm(Module *module, const vector &cells) :".format(prefix), file=f) print(" module(module), sigmap(module) {", file=f) - print(" for (auto cell : cells) {", file=f) + for s, t in sorted(udata_types.items()): + if t.endswith("*"): + print(" ud.{} = nullptr;".format(s), file=f) + else: + print(" ud.{} = {}();".format(s, t), file=f) + print(" for (auto cell : module->cells()) {", file=f) print(" for (auto &conn : cell->connections())", file=f) print(" add_siguser(conn.second, cell);", file=f) print(" }", file=f) @@ -281,7 +302,7 @@ with open("%s_pm.h" % prefix, "w") as f: print(" }", file=f) print("", file=f) - print(" void match(std::function on_accept_f) {{".format(prefix), file=f) + print(" void run(std::function on_accept_f) {{".format(prefix), file=f) print(" on_accept = on_accept_f;", file=f) print(" rollback = 0;", file=f) for s, t in sorted(state_types.items()): @@ -293,10 +314,6 @@ with open("%s_pm.h" % prefix, "w") as f: print(" }", file=f) print("", file=f) - print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f) - print("#define accept do { on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f) - print("", file=f) - for index in range(len(blocks)): block = blocks[index] @@ -348,13 +365,22 @@ with open("%s_pm.h" % prefix, "w") as f: if block["type"] == "code": print("", file=f) print(" do {", file=f) + print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f) + print("#define accept do { on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f) + print("#define branch do {{ block_{}(); }} while(0)".format(index+1), file=f) + for line in block["code"]: print(" " + line, file=f) print("", file=f) print(" block_{}();".format(index+1), file=f) - print("rollback_label: YS_ATTRIBUTE(unused);", file=f) + print("#undef reject", file=f) + print("#undef accept", file=f) + print("#undef branch", file=f) print(" } while (0);", file=f) + print("", file=f) + print("rollback_label:", file=f) + print(" YS_ATTRIBUTE(unused);", file=f) if len(restore_st) or len(nonconst_st): print("", file=f) @@ -415,10 +441,6 @@ with open("%s_pm.h" % prefix, "w") as f: print(" }", file=f) print("", file=f) - print("#undef reject", file=f) - print("#undef accept", file=f) - print("", file=f) - print(" void block_{}() {{".format(len(blocks)), file=f) print(" on_accept();", file=f) print(" check_blacklist();", file=f) From 8ddec5d882c6834cb6b3415e05a2a88d416cabff Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 14 Jan 2019 13:42:42 +0100 Subject: [PATCH 07/53] Progress in pmgen Signed-off-by: Clifford Wolf --- passes/pmgen/pmgen.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index 885f6db1c..a59cf5a81 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -203,6 +203,7 @@ with open("%s_pm.h" % prefix, "w") as f: print(" dict> index_{};".format(index, index), file=f) print(" dict> sigusers;", file=f) print(" pool blacklist_cells;", file=f) + print(" bool blacklist_dirty;", file=f) print(" int rollback;", file=f) print("", file=f) @@ -236,12 +237,17 @@ with open("%s_pm.h" % prefix, "w") as f: print("", file=f) print(" void blacklist(Cell *cell) {", file=f) - print(" if (cell != nullptr)", file=f) - print(" blacklist_cells.insert(cell);", file=f) + print(" if (cell != nullptr) {", file=f) + print(" if (blacklist_cells.insert(cell).second)", file=f) + print(" blacklist_dirty = true;", file=f) + print(" }", file=f) print(" }", file=f) print("", file=f) print(" void check_blacklist() {", file=f) + print(" if (!blacklist_dirty)", file=f) + print(" return;", file=f) + print(" blacklist_dirty = false;", file=f) for index in range(len(blocks)): block = blocks[index] if block["type"] == "match": @@ -305,6 +311,7 @@ with open("%s_pm.h" % prefix, "w") as f: print(" void run(std::function on_accept_f) {{".format(prefix), file=f) print(" on_accept = on_accept_f;", file=f) print(" rollback = 0;", file=f) + print(" blacklist_dirty = false;", file=f) for s, t in sorted(state_types.items()): if t.endswith("*"): print(" st.{} = nullptr;".format(s), file=f) @@ -367,7 +374,7 @@ with open("%s_pm.h" % prefix, "w") as f: print(" do {", file=f) print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f) print("#define accept do { on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f) - print("#define branch do {{ block_{}(); }} while(0)".format(index+1), file=f) + print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f) for line in block["code"]: print(" " + line, file=f) @@ -416,6 +423,7 @@ with open("%s_pm.h" % prefix, "w") as f: print("", file=f) print(" for (int idx = 0; idx < GetSize(cells); idx++) {", file=f) print(" {} = cells[idx];".format(block["cell"]), file=f) + print(" if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f) for expr in block["filter"]: print(" if (!({})) continue;".format(expr), file=f) print(" block_{}();".format(index+1), file=f) From a9674bd2eca5efac6e4f7b2871a01cbba80f64ec Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 6 Feb 2019 12:49:30 -0800 Subject: [PATCH 08/53] Add testcase --- tests/simple/dff_init.v | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/simple/dff_init.v diff --git a/tests/simple/dff_init.v b/tests/simple/dff_init.v new file mode 100644 index 000000000..aad378346 --- /dev/null +++ b/tests/simple/dff_init.v @@ -0,0 +1,10 @@ +module dff_test(n1, n1_inv, clk); + input clk; + (* init = 32'd0 *) + output n1; + reg n1 = 32'd0; + output n1_inv; + always @(posedge clk) + n1 <= n1_inv; + assign n1_inv = ~n1; +endmodule From 8524a479b15ff89db48872c57103c60be77142af Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 4 Dec 2018 14:17:47 +0000 Subject: [PATCH 09/53] abc: Preserve naming through ABC using 'dress' command Signed-off-by: David Shah --- passes/techmap/abc.cc | 80 +++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index d2d15a4a9..d3bdd555b 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -329,6 +329,18 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) std::string remap_name(RTLIL::IdString abc_name) { + std::string abc_sname = abc_name.substr(1); + if (abc_sname.substr(0, 5) == "ys__n") { + int sid = std::stoi(abc_sname.substr(5)); + bool inv = abc_sname.back() == 'v'; + for (auto sig : signal_list) { + if (sig.id == sid) { + std::stringstream sstr; + sstr << "$abc$" << map_autoidx << "$" << log_signal(sig.bit) << (inv ? "_inv" : ""); + return sstr.str(); + } + } + } std::stringstream sstr; sstr << "$abc$" << map_autoidx << "$" << abc_name.substr(1); return sstr.str(); @@ -353,12 +365,12 @@ void dump_loop_graph(FILE *f, int &nr, std::map> &edges, std: } for (auto n : nodes) - fprintf(f, " n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].bit), + fprintf(f, " ys__n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].bit), n, in_counts[n], workpool.count(n) ? ", shape=box" : ""); for (auto &e : edges) for (auto n : e.second) - fprintf(f, " n%d -> n%d;\n", e.first, n); + fprintf(f, " ys__n%d -> ys__n%d;\n", e.first, n); fprintf(f, "}\n"); } @@ -624,7 +636,7 @@ struct abc_output_filter void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, std::string liberty_file, std::string constr_file, bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, - const std::vector &cells, bool show_tempdir, bool sop_mode) + const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress) { module = current_module; map_autoidx = autoidx++; @@ -728,7 +740,8 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos)) abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3); - + if (abc_dress) + abc_script += "; dress"; abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str()); abc_script = add_echos_to_abc_cmd(abc_script); @@ -784,7 +797,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin for (auto &si : signal_list) { if (!si.is_port || si.type != G(NONE)) continue; - fprintf(f, " n%d", si.id); + fprintf(f, " ys__n%d", si.id); pi_map[count_input++] = log_signal(si.bit); } if (count_input == 0) @@ -796,17 +809,17 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin for (auto &si : signal_list) { if (!si.is_port || si.type == G(NONE)) continue; - fprintf(f, " n%d", si.id); + fprintf(f, " ys__n%d", si.id); po_map[count_output++] = log_signal(si.bit); } fprintf(f, "\n"); for (auto &si : signal_list) - fprintf(f, "# n%-5d %s\n", si.id, log_signal(si.bit)); + fprintf(f, "# ys__n%-5d %s\n", si.id, log_signal(si.bit)); for (auto &si : signal_list) { if (si.bit.wire == NULL) { - fprintf(f, ".names n%d\n", si.id); + fprintf(f, ".names ys__n%d\n", si.id); if (si.bit == RTLIL::State::S1) fprintf(f, "1\n"); } @@ -815,68 +828,68 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin int count_gates = 0; for (auto &si : signal_list) { if (si.type == G(BUF)) { - fprintf(f, ".names n%d n%d\n", si.in1, si.id); + fprintf(f, ".names ys__n%d ys__n%d\n", si.in1, si.id); fprintf(f, "1 1\n"); } else if (si.type == G(NOT)) { - fprintf(f, ".names n%d n%d\n", si.in1, si.id); + fprintf(f, ".names ys__n%d ys__n%d\n", si.in1, si.id); fprintf(f, "0 1\n"); } else if (si.type == G(AND)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "11 1\n"); } else if (si.type == G(NAND)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "0- 1\n"); fprintf(f, "-0 1\n"); } else if (si.type == G(OR)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "-1 1\n"); fprintf(f, "1- 1\n"); } else if (si.type == G(NOR)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "00 1\n"); } else if (si.type == G(XOR)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "01 1\n"); fprintf(f, "10 1\n"); } else if (si.type == G(XNOR)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "00 1\n"); fprintf(f, "11 1\n"); } else if (si.type == G(ANDNOT)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "10 1\n"); } else if (si.type == G(ORNOT)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "1- 1\n"); fprintf(f, "-0 1\n"); } else if (si.type == G(MUX)) { - fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id); fprintf(f, "1-0 1\n"); fprintf(f, "-11 1\n"); } else if (si.type == G(AOI3)) { - fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id); fprintf(f, "-00 1\n"); fprintf(f, "0-0 1\n"); } else if (si.type == G(OAI3)) { - fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id); fprintf(f, "00- 1\n"); fprintf(f, "--0 1\n"); } else if (si.type == G(AOI4)) { - fprintf(f, ".names n%d n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.in4, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.in4, si.id); fprintf(f, "-0-0 1\n"); fprintf(f, "-00- 1\n"); fprintf(f, "0--0 1\n"); fprintf(f, "0-0- 1\n"); } else if (si.type == G(OAI4)) { - fprintf(f, ".names n%d n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.in4, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.in4, si.id); fprintf(f, "00-- 1\n"); fprintf(f, "--00 1\n"); } else if (si.type == G(FF)) { if (si.init == State::S0 || si.init == State::S1) { - fprintf(f, ".latch n%d n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0); + fprintf(f, ".latch ys__n%d ys__n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0); recover_init = true; } else - fprintf(f, ".latch n%d n%d 2\n", si.in1, si.id); + fprintf(f, ".latch ys__n%d ys__n%d 2\n", si.in1, si.id); } else if (si.type != G(NONE)) log_abort(); if (si.type != G(NONE)) @@ -889,7 +902,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n", count_gates, GetSize(signal_list), count_input, count_output); log_push(); - if (count_output > 0) { log_header(design, "Executing ABC.\n"); @@ -1213,7 +1225,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin for (auto &si : signal_list) if (si.is_port) { char buffer[100]; - snprintf(buffer, 100, "\\n%d", si.id); + snprintf(buffer, 100, "\\ys__n%d", si.id); RTLIL::SigSig conn; if (si.type != G(NONE)) { conn.first = si.bit; @@ -1407,6 +1419,11 @@ struct AbcPass : public Pass { log(" this attribute is a unique integer for each ABC process started. This\n"); log(" is useful for debugging the partitioning of clock domains.\n"); log("\n"); + log(" -dress\n"); + log(" run the 'dress' command after all other ABC commands. This aims to\n"); + log(" preserve naming by an equivalence check between the original and post-ABC\n"); + log(" netlists (experimental).\n"); + log("\n"); log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n"); log("loaded into ABC before the ABC script is executed.\n"); log("\n"); @@ -1441,6 +1458,7 @@ struct AbcPass : public Pass { std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1"; bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; bool show_tempdir = false, sop_mode = false; + bool abc_dress = false; vector lut_costs; markgroups = false; @@ -1555,6 +1573,10 @@ struct AbcPass : public Pass { map_mux16 = true; continue; } + if (arg == "-dress") { + abc_dress = true; + continue; + } if (arg == "-g" && argidx+1 < args.size()) { for (auto g : split_tokens(args[++argidx], ",")) { vector gate_list; @@ -1704,7 +1726,7 @@ struct AbcPass : public Pass { if (!dff_mode || !clk_str.empty()) { abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, - delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode); + delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress); continue; } @@ -1849,7 +1871,7 @@ struct AbcPass : public Pass { en_polarity = std::get<2>(it.first); en_sig = assign_map(std::get<3>(it.first)); abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$", - keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode); + keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress); assign_map.set(mod); } } From 7ef2333497940a9f235d36f38a727f2533bab902 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 16 Dec 2018 17:43:57 +0000 Subject: [PATCH 10/53] ice40: Use abc -dress in synth_ice40 Signed-off-by: David Shah --- techlibs/ice40/synth_ice40.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index f900453e8..ba013fef2 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -282,7 +282,7 @@ struct SynthIce40Pass : public ScriptPass run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)"); } if (!noabc) { - run("abc -lut 4", "(skip if -noabc)"); + run("abc -dress -lut 4", "(skip if -noabc)"); } run("clean"); if (relut || help_mode) { From 58c22dae31cd65010bd525ad7b4241709e773314 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 16 Dec 2018 17:44:37 +0000 Subject: [PATCH 11/53] abc: Improved recovered netnames, also preserve src on nets with dress Signed-off-by: David Shah --- passes/techmap/abc.cc | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index d3bdd555b..21b70f492 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -327,16 +327,22 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) } } -std::string remap_name(RTLIL::IdString abc_name) +std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr) { std::string abc_sname = abc_name.substr(1); if (abc_sname.substr(0, 5) == "ys__n") { int sid = std::stoi(abc_sname.substr(5)); bool inv = abc_sname.back() == 'v'; for (auto sig : signal_list) { - if (sig.id == sid) { + if (sig.id == sid && sig.bit.wire != nullptr) { std::stringstream sstr; - sstr << "$abc$" << map_autoidx << "$" << log_signal(sig.bit) << (inv ? "_inv" : ""); + sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1); + if (sig.bit.wire->width != 1) + sstr << "[" << sig.bit.offset << "]"; + if (inv) + sstr << "_inv"; + if (orig_wire != nullptr) + *orig_wire = sig.bit.wire; return sstr.str(); } } @@ -1000,7 +1006,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin log_error("ABC output file does not contain a module `netlist'.\n"); for (auto &it : mapped_mod->wires_) { RTLIL::Wire *w = it.second; - RTLIL::Wire *wire = module->addWire(remap_name(w->name)); + RTLIL::Wire *orig_wire = nullptr; + RTLIL::Wire *wire = module->addWire(remap_name(w->name, &orig_wire)); + if (orig_wire != nullptr && orig_wire->attributes.count("\\src")) + wire->attributes["\\src"] = orig_wire->attributes["\\src"]; if (markgroups) wire->attributes["\\abcgroup"] = map_autoidx; design->select(module, wire); } From 95789c61360d3842265409bd948115f471e005b4 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 6 Feb 2019 22:20:39 +0100 Subject: [PATCH 12/53] ecp5: Use abc -dress Signed-off-by: David Shah --- techlibs/ecp5/synth_ecp5.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 2e9176a84..bda03d251 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -268,9 +268,9 @@ struct SynthEcp5Pass : public ScriptPass } run("techmap -map +/ecp5/latches_map.v"); if (nomux) - run("abc -lut 4"); + run("abc -lut 4 -dress"); else - run("abc -lut 4:7"); + run("abc -lut 4:7 -dress"); run("clean"); } From 03cf1532a70d705ada69dcb8ae79ae405a86b7da Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 6 Feb 2019 14:02:11 -0800 Subject: [PATCH 13/53] Extend testcase --- tests/simple/dff_init.v | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/tests/simple/dff_init.v b/tests/simple/dff_init.v index aad378346..be947042e 100644 --- a/tests/simple/dff_init.v +++ b/tests/simple/dff_init.v @@ -1,6 +1,5 @@ -module dff_test(n1, n1_inv, clk); +module dff0_test(n1, n1_inv, clk); input clk; - (* init = 32'd0 *) output n1; reg n1 = 32'd0; output n1_inv; @@ -8,3 +7,36 @@ module dff_test(n1, n1_inv, clk); n1 <= n1_inv; assign n1_inv = ~n1; endmodule + +module dff1_test(n1, n1_inv, clk); + input clk; + (* init = 32'd1 *) + output n1; + reg n1 = 32'd1; + output n1_inv; + always @(posedge clk) + n1 <= n1_inv; + assign n1_inv = ~n1; +endmodule + +module dff0a_test(n1, n1_inv, clk); + input clk; + (* init = 32'd0 *) // Must be consistent with reg initialiser below + output n1; + reg n1 = 32'd0; + output n1_inv; + always @(posedge clk) + n1 <= n1_inv; + assign n1_inv = ~n1; +endmodule + +module dff1a_test(n1, n1_inv, clk); + input clk; + (* init = 32'd1 *) // Must be consistent with reg initialiser below + output n1; + reg n1 = 32'd1; + output n1_inv; + always @(posedge clk) + n1 <= n1_inv; + assign n1_inv = ~n1; +endmodule From 281f2aadcab01465f83a3f3a697eec42503e9f8b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 6 Feb 2019 14:14:55 -0800 Subject: [PATCH 14/53] Add -B option to autotest.sh to append to backend_opts --- tests/tools/autotest.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index d6216244f..800fa3ad5 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -22,7 +22,7 @@ if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdat ( set -ex; ${CC:-gcc} -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1 fi -while getopts xmGl:wkjvref:s:p:n:S:I: opt; do +while getopts xmGl:wkjvref:s:p:n:S:I:B: opt; do case "$opt" in x) use_xsim=true ;; @@ -59,8 +59,10 @@ while getopts xmGl:wkjvref:s:p:n:S:I: opt; do include_opts="$include_opts -I $OPTARG" xinclude_opts="$xinclude_opts -i $OPTARG" minclude_opts="$minclude_opts +incdir+$OPTARG" ;; + B) + backend_opts="$backend_opts $OPTARG" ;; *) - echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] verilog-files\n" >&2 + echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] [-B backend_opt] verilog-files\n" >&2 exit 1 esac done From 115883f467cb79688ffb93c136a6ee61368765e8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 6 Feb 2019 14:15:17 -0800 Subject: [PATCH 15/53] Add tests for simple cases using defparam --- tests/simple_defparam/run-test.sh | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100755 tests/simple_defparam/run-test.sh diff --git a/tests/simple_defparam/run-test.sh b/tests/simple_defparam/run-test.sh new file mode 100755 index 000000000..137e15076 --- /dev/null +++ b/tests/simple_defparam/run-test.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +OPTIND=1 +seed="" # default to no seed specified +while getopts "S:" opt +do + case "$opt" in + S) arg="${OPTARG#"${OPTARG%%[![:space:]]*}"}" # remove leading space + seed="SEED=$arg" ;; + esac +done +shift "$((OPTIND-1))" + +# check for Icarus Verilog +if ! which iverilog > /dev/null ; then + echo "$0: Error: Icarus Verilog 'iverilog' not found." + exit 1 +fi + +cp ../simple/*.v . +exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-B \"-defparam\"" From 742b4e01b498ae2e735d40565f43607d69a015d8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 6 Feb 2019 14:16:26 -0800 Subject: [PATCH 16/53] Add INIT parameter to all ff/latch cells --- techlibs/common/simcells.v | 111 ++++++++++++++++++++++++------------- techlibs/common/simlib.v | 18 ++++-- 2 files changed, 86 insertions(+), 43 deletions(-) diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v index 289673e82..b9957bd5e 100644 --- a/techlibs/common/simcells.v +++ b/techlibs/common/simcells.v @@ -451,8 +451,9 @@ endmodule //- 1 1 | y //- module \$_SR_NN_ (S, R, Q); +parameter INIT = 1'bx; input S, R; -output reg Q; +output reg Q = INIT; always @(negedge S, negedge R) begin if (R == 0) Q <= 0; @@ -475,8 +476,9 @@ endmodule //- 1 0 | y //- module \$_SR_NP_ (S, R, Q); +parameter INIT = 1'bx; input S, R; -output reg Q; +output reg Q = INIT; always @(negedge S, posedge R) begin if (R == 1) Q <= 0; @@ -499,8 +501,9 @@ endmodule //- 0 1 | y //- module \$_SR_PN_ (S, R, Q); +parameter INIT = 1'bx; input S, R; -output reg Q; +output reg Q = INIT; always @(posedge S, negedge R) begin if (R == 0) Q <= 0; @@ -523,8 +526,9 @@ endmodule //- 0 0 | y //- module \$_SR_PP_ (S, R, Q); +parameter INIT = 1'bx; input S, R; -output reg Q; +output reg Q = INIT; always @(posedge S, posedge R) begin if (R == 1) Q <= 0; @@ -542,8 +546,9 @@ endmodule //- type is usually only used in netlists for formal verification.) //- module \$_FF_ (D, Q); +parameter INIT = 1'bx; input D; -output reg Q; +output reg Q = INIT; always @($global_clock) begin Q <= D; end @@ -562,8 +567,9 @@ endmodule //- - - | q //- module \$_DFF_N_ (D, C, Q); +parameter INIT = 1'bx; input D, C; -output reg Q; +output reg Q = INIT; always @(negedge C) begin Q <= D; end @@ -581,8 +587,9 @@ endmodule //- - - | q //- module \$_DFF_P_ (D, C, Q); +parameter INIT = 1'bx; input D, C; -output reg Q; +output reg Q = INIT; always @(posedge C) begin Q <= D; end @@ -600,8 +607,9 @@ endmodule //- - - - | q //- module \$_DFFE_NN_ (D, C, E, Q); +parameter INIT = 1'bx; input D, C, E; -output reg Q; +output reg Q = INIT; always @(negedge C) begin if (!E) Q <= D; end @@ -619,8 +627,9 @@ endmodule //- - - - | q //- module \$_DFFE_NP_ (D, C, E, Q); +parameter INIT = 1'bx; input D, C, E; -output reg Q; +output reg Q = INIT; always @(negedge C) begin if (E) Q <= D; end @@ -638,8 +647,9 @@ endmodule //- - - - | q //- module \$_DFFE_PN_ (D, C, E, Q); +parameter INIT = 1'bx; input D, C, E; -output reg Q; +output reg Q = INIT; always @(posedge C) begin if (!E) Q <= D; end @@ -657,8 +667,9 @@ endmodule //- - - - | q //- module \$_DFFE_PP_ (D, C, E, Q); +parameter INIT = 1'bx; input D, C, E; -output reg Q; +output reg Q = INIT; always @(posedge C) begin if (E) Q <= D; end @@ -677,8 +688,9 @@ endmodule //- - - - | q //- module \$_DFF_NN0_ (D, C, R, Q); +parameter INIT = 1'bx; input D, C, R; -output reg Q; +output reg Q = INIT; always @(negedge C or negedge R) begin if (R == 0) Q <= 0; @@ -700,8 +712,9 @@ endmodule //- - - - | q //- module \$_DFF_NN1_ (D, C, R, Q); +parameter INIT = 1'bx; input D, C, R; -output reg Q; +output reg Q = INIT; always @(negedge C or negedge R) begin if (R == 0) Q <= 1; @@ -723,8 +736,9 @@ endmodule //- - - - | q //- module \$_DFF_NP0_ (D, C, R, Q); +parameter INIT = 1'bx; input D, C, R; -output reg Q; +output reg Q = INIT; always @(negedge C or posedge R) begin if (R == 1) Q <= 0; @@ -746,8 +760,9 @@ endmodule //- - - - | q //- module \$_DFF_NP1_ (D, C, R, Q); +parameter INIT = 1'bx; input D, C, R; -output reg Q; +output reg Q = INIT; always @(negedge C or posedge R) begin if (R == 1) Q <= 1; @@ -769,8 +784,9 @@ endmodule //- - - - | q //- module \$_DFF_PN0_ (D, C, R, Q); +parameter INIT = 1'bx; input D, C, R; -output reg Q; +output reg Q = INIT; always @(posedge C or negedge R) begin if (R == 0) Q <= 0; @@ -792,8 +808,9 @@ endmodule //- - - - | q //- module \$_DFF_PN1_ (D, C, R, Q); +parameter INIT = 1'bx; input D, C, R; -output reg Q; +output reg Q = INIT; always @(posedge C or negedge R) begin if (R == 0) Q <= 1; @@ -815,8 +832,9 @@ endmodule //- - - - | q //- module \$_DFF_PP0_ (D, C, R, Q); +parameter INIT = 1'bx; input D, C, R; -output reg Q; +output reg Q = INIT; always @(posedge C or posedge R) begin if (R == 1) Q <= 0; @@ -838,8 +856,9 @@ endmodule //- - - - | q //- module \$_DFF_PP1_ (D, C, R, Q); +parameter INIT = 1'bx; input D, C, R; -output reg Q; +output reg Q = INIT; always @(posedge C or posedge R) begin if (R == 1) Q <= 1; @@ -862,8 +881,9 @@ endmodule //- - - - - | q //- module \$_DFFSR_NNN_ (C, S, R, D, Q); +parameter INIT = 1'bx; input C, S, R, D; -output reg Q; +output reg Q = INIT; always @(negedge C, negedge S, negedge R) begin if (R == 0) Q <= 0; @@ -889,8 +909,9 @@ endmodule //- - - - - | q //- module \$_DFFSR_NNP_ (C, S, R, D, Q); +parameter INIT = 1'bx; input C, S, R, D; -output reg Q; +output reg Q = INIT; always @(negedge C, negedge S, posedge R) begin if (R == 1) Q <= 0; @@ -916,8 +937,9 @@ endmodule //- - - - - | q //- module \$_DFFSR_NPN_ (C, S, R, D, Q); +parameter INIT = 1'bx; input C, S, R, D; -output reg Q; +output reg Q = INIT; always @(negedge C, posedge S, negedge R) begin if (R == 0) Q <= 0; @@ -942,8 +964,9 @@ endmodule //- - - - - | q //- module \$_DFFSR_NPP_ (C, S, R, D, Q); +parameter INIT = 1'bx; input C, S, R, D; -output reg Q; +output reg Q = INIT; always @(negedge C, posedge S, posedge R) begin if (R == 1) Q <= 0; @@ -968,8 +991,9 @@ endmodule //- - - - - | q //- module \$_DFFSR_PNN_ (C, S, R, D, Q); +parameter INIT = 1'bx; input C, S, R, D; -output reg Q; +output reg Q = INIT; always @(posedge C, negedge S, negedge R) begin if (R == 0) Q <= 0; @@ -995,8 +1019,9 @@ endmodule //- - - - - | q //- module \$_DFFSR_PNP_ (C, S, R, D, Q); +parameter INIT = 1'bx; input C, S, R, D; -output reg Q; +output reg Q = INIT; always @(posedge C, negedge S, posedge R) begin if (R == 1) Q <= 0; @@ -1022,8 +1047,9 @@ endmodule //- - - - - | q //- module \$_DFFSR_PPN_ (C, S, R, D, Q); +parameter INIT = 1'bx; input C, S, R, D; -output reg Q; +output reg Q = INIT; always @(posedge C, posedge S, negedge R) begin if (R == 0) Q <= 0; @@ -1048,8 +1074,9 @@ endmodule //- - - - - | q //- module \$_DFFSR_PPP_ (C, S, R, D, Q); +parameter INIT = 1'bx; input C, S, R, D; -output reg Q; +output reg Q = INIT; always @(posedge C, posedge S, posedge R) begin if (R == 1) Q <= 0; @@ -1072,8 +1099,9 @@ endmodule //- - - | q //- module \$_DLATCH_N_ (E, D, Q); +parameter INIT = 1'bx; input E, D; -output reg Q; +output reg Q = INIT; always @* begin if (E == 0) Q <= D; @@ -1092,8 +1120,9 @@ endmodule //- - - | q //- module \$_DLATCH_P_ (E, D, Q); +parameter INIT = 1'bx; input E, D; -output reg Q; +output reg Q = INIT; always @* begin if (E == 1) Q <= D; @@ -1114,8 +1143,9 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_NNN_ (E, S, R, D, Q); +parameter INIT = 1'bx; input E, S, R, D; -output reg Q; +output reg Q = INIT; always @* begin if (R == 0) Q <= 0; @@ -1141,8 +1171,9 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_NNP_ (E, S, R, D, Q); +parameter INIT = 1'bx; input E, S, R, D; -output reg Q; +output reg Q = INIT; always @* begin if (R == 1) Q <= 0; @@ -1168,8 +1199,9 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_NPN_ (E, S, R, D, Q); +parameter INIT = 1'bx; input E, S, R, D; -output reg Q; +output reg Q = INIT; always @* begin if (R == 0) Q <= 0; @@ -1194,8 +1226,9 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_NPP_ (E, S, R, D, Q); +parameter INIT = 1'bx; input E, S, R, D; -output reg Q; +output reg Q = INIT; always @* begin if (R == 1) Q <= 0; @@ -1220,8 +1253,9 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_PNN_ (E, S, R, D, Q); +parameter INIT = 1'bx; input E, S, R, D; -output reg Q; +output reg Q = INIT; always @* begin if (R == 0) Q <= 0; @@ -1247,8 +1281,9 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_PNP_ (E, S, R, D, Q); +parameter INIT = 1'bx; input E, S, R, D; -output reg Q; +output reg Q = INIT; always @* begin if (R == 1) Q <= 0; @@ -1274,8 +1309,9 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_PPN_ (E, S, R, D, Q); +parameter INIT = 1'bx; input E, S, R, D; -output reg Q; +output reg Q = INIT; always @* begin if (R == 0) Q <= 0; @@ -1300,8 +1336,9 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_PPP_ (E, S, R, D, Q); +parameter INIT = 1'bx; input E, S, R, D; -output reg Q; +output reg Q = INIT; always @* begin if (R == 1) Q <= 0; diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 8e43fe058..9b6008140 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1464,10 +1464,11 @@ module \$dff (CLK, D, Q); parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; +parameter INIT = {WIDTH{1'bx}}; input CLK; input [WIDTH-1:0] D; -output reg [WIDTH-1:0] Q; +output reg [WIDTH-1:0] Q = INIT; wire pos_clk = CLK == CLK_POLARITY; always @(posedge pos_clk) begin @@ -1483,10 +1484,11 @@ module \$dffe (CLK, EN, D, Q); parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter EN_POLARITY = 1'b1; +parameter INIT = {WIDTH{1'bx}}; input CLK, EN; input [WIDTH-1:0] D; -output reg [WIDTH-1:0] Q; +output reg [WIDTH-1:0] Q = INIT; wire pos_clk = CLK == CLK_POLARITY; always @(posedge pos_clk) begin @@ -1504,10 +1506,11 @@ parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter SET_POLARITY = 1'b1; parameter CLR_POLARITY = 1'b1; +parameter INIT = {WIDTH{1'bx}}; input CLK; input [WIDTH-1:0] SET, CLR, D; -output reg [WIDTH-1:0] Q; +output reg [WIDTH-1:0] Q = INIT; wire pos_clk = CLK == CLK_POLARITY; wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET; @@ -1537,10 +1540,11 @@ parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter ARST_POLARITY = 1'b1; parameter ARST_VALUE = 0; +parameter INIT = {WIDTH{1'bx}}; input CLK, ARST; input [WIDTH-1:0] D; -output reg [WIDTH-1:0] Q; +output reg [WIDTH-1:0] Q = INIT; wire pos_clk = CLK == CLK_POLARITY; wire pos_arst = ARST == ARST_POLARITY; @@ -1559,10 +1563,11 @@ module \$dlatch (EN, D, Q); parameter WIDTH = 0; parameter EN_POLARITY = 1'b1; +parameter INIT = {WIDTH{1'bx}}; input EN; input [WIDTH-1:0] D; -output reg [WIDTH-1:0] Q; +output reg [WIDTH-1:0] Q = INIT; always @* begin if (EN == EN_POLARITY) @@ -1580,10 +1585,11 @@ parameter WIDTH = 0; parameter EN_POLARITY = 1'b1; parameter SET_POLARITY = 1'b1; parameter CLR_POLARITY = 1'b1; +parameter INIT = {WIDTH{1'bx}}; input EN; input [WIDTH-1:0] SET, CLR, D; -output reg [WIDTH-1:0] Q; +output reg [WIDTH-1:0] Q = INIT; wire pos_en = EN == EN_POLARITY; wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET; From 8241db6960d17469678e8c71fd7d6c1b7ddc4fe7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 6 Feb 2019 14:17:09 -0800 Subject: [PATCH 17/53] write_verilog to cope with init attr on q when -noexpr --- backends/verilog/verilog_backend.cc | 34 +++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index a7f329ef8..04191443a 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1247,7 +1247,30 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) dump_attributes(f, indent, cell->attributes); f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str()); - if (!defparam && cell->parameters.size() > 0) { + std::string init; + if (cell->name[0] == '$' && reg_ct.count(cell->type) && cell->hasPort("\\Q")) { + auto q_wire = cell->getPort("\\Q"); + + Const initval; + bool gotinit = false; + + for (auto bit : active_sigmap(q_wire)) { + if (active_initdata.count(bit)) { + initval.bits.push_back(active_initdata.at(bit)); + gotinit = true; + } else { + initval.bits.push_back(State::Sx); + } + } + + if (gotinit) { + std::stringstream ss; + dump_const(ss, initval); + init = ss.str(); + } + } + + if (!defparam && (cell->parameters.size() > 0 || !init.empty())) { f << stringf(" #("); for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { if (it != cell->parameters.begin()) @@ -1257,6 +1280,11 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) dump_const(f, it->second, -1, 0, false, is_signed); f << stringf(")"); } + if (!init.empty()) { + if (!cell->parameters.empty()) + f << stringf(","); + f << stringf("\n%s .INIT(%s)", indent.c_str(), init.c_str()); + } f << stringf("\n%s" ")", indent.c_str()); } @@ -1298,13 +1326,15 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) } f << stringf("\n%s" ");\n", indent.c_str()); - if (defparam && cell->parameters.size() > 0) { + if (defparam && (cell->parameters.size() > 0 || !init.empty())) { for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str()); bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0; dump_const(f, it->second, -1, 0, false, is_signed); f << stringf(";\n"); } + if (!init.empty()) + f << stringf("%sdefparam %s.INIT = %s;\n", indent.c_str(), cell_name.c_str(), init.c_str()); } } From c373640a3ac6c2f76f0a8dce4e44236154ca24bc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 6 Feb 2019 14:28:44 -0800 Subject: [PATCH 18/53] Refactor --- backends/verilog/verilog_backend.cc | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 04191443a..66a9e70d3 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -293,7 +293,7 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o } } -void dump_reg_init(std::ostream &f, SigSpec sig) +void dump_reg_init(std::ostream &f, SigSpec sig, bool write_equals = true) { Const initval; bool gotinit = false; @@ -308,7 +308,7 @@ void dump_reg_init(std::ostream &f, SigSpec sig) } if (gotinit) { - f << " = "; + if (write_equals) f << " = "; dump_const(f, initval); } } @@ -1249,25 +1249,9 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) std::string init; if (cell->name[0] == '$' && reg_ct.count(cell->type) && cell->hasPort("\\Q")) { - auto q_wire = cell->getPort("\\Q"); - - Const initval; - bool gotinit = false; - - for (auto bit : active_sigmap(q_wire)) { - if (active_initdata.count(bit)) { - initval.bits.push_back(active_initdata.at(bit)); - gotinit = true; - } else { - initval.bits.push_back(State::Sx); - } - } - - if (gotinit) { - std::stringstream ss; - dump_const(ss, initval); - init = ss.str(); - } + std::stringstream ss; + dump_reg_init(ss, cell->getPort("\\Q"), false /* write_equals */); + init = ss.str(); } if (!defparam && (cell->parameters.size() > 0 || !init.empty())) { From 20ca795b87b810063cdcee6e92e3922281f6b092 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 6 Feb 2019 14:53:40 -0800 Subject: [PATCH 19/53] Remove check for cell->name[0] == '$' --- backends/verilog/verilog_backend.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 66a9e70d3..7b3a60e61 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1248,7 +1248,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str()); std::string init; - if (cell->name[0] == '$' && reg_ct.count(cell->type) && cell->hasPort("\\Q")) { + if (reg_ct.count(cell->type) && cell->hasPort("\\Q")) { std::stringstream ss; dump_reg_init(ss, cell->getPort("\\Q"), false /* write_equals */); init = ss.str(); From e8f4dc739c5cf1129800aaa88df3f7c6f9c99360 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 6 Feb 2019 15:51:12 -0800 Subject: [PATCH 20/53] Cope WIDTH of ff/latch cells is default of zero --- techlibs/common/simlib.v | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 9b6008140..a1e0c1575 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1464,7 +1464,7 @@ module \$dff (CLK, D, Q); parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; -parameter INIT = {WIDTH{1'bx}}; +parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input CLK; input [WIDTH-1:0] D; @@ -1484,7 +1484,7 @@ module \$dffe (CLK, EN, D, Q); parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter EN_POLARITY = 1'b1; -parameter INIT = {WIDTH{1'bx}}; +parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input CLK, EN; input [WIDTH-1:0] D; @@ -1506,7 +1506,7 @@ parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter SET_POLARITY = 1'b1; parameter CLR_POLARITY = 1'b1; -parameter INIT = {WIDTH{1'bx}}; +parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input CLK; input [WIDTH-1:0] SET, CLR, D; @@ -1540,7 +1540,7 @@ parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter ARST_POLARITY = 1'b1; parameter ARST_VALUE = 0; -parameter INIT = {WIDTH{1'bx}}; +parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input CLK, ARST; input [WIDTH-1:0] D; @@ -1563,7 +1563,7 @@ module \$dlatch (EN, D, Q); parameter WIDTH = 0; parameter EN_POLARITY = 1'b1; -parameter INIT = {WIDTH{1'bx}}; +parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input EN; input [WIDTH-1:0] D; @@ -1585,7 +1585,7 @@ parameter WIDTH = 0; parameter EN_POLARITY = 1'b1; parameter SET_POLARITY = 1'b1; parameter CLR_POLARITY = 1'b1; -parameter INIT = {WIDTH{1'bx}}; +parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input EN; input [WIDTH-1:0] SET, CLR, D; From fc1c9aa11fbfbb1ea5b63e1830549d453ba01dfb Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Fri, 15 Feb 2019 11:14:17 -0800 Subject: [PATCH 21/53] Update cells supported for verilog to FIRRTL conversion. Issue warning messages for missing parameterized modules and attempts to set initial values. Replace simple "if (cell-type)" with "else if" chain. Fix FIRRTL shift handling. Add support for parameterized modules, $shift, $shiftx. Handle default output file. Deal with no top module. Automatically run pmuxtree pass. Allow EXTRA_FLAGS and SEED parameters to be set in the environment for tests/tools/autotest.mk. Support FIRRTL regression testing in tests/tools/autotest.sh Add xfirrtl files to test directories to exclude files from FIRRTL regression tests that are known to fail. --- backends/firrtl/firrtl.cc | 273 +++++++++++++++++++++++++++++++------- tests/asicworld/xfirrtl | 24 ++++ tests/simple/xfirrtl | 26 ++++ tests/tools/autotest.mk | 6 +- tests/tools/autotest.sh | 43 +++++- 5 files changed, 317 insertions(+), 55 deletions(-) create mode 100644 tests/asicworld/xfirrtl create mode 100644 tests/simple/xfirrtl diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index 32410a651..7ca5dc756 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -23,7 +23,11 @@ #include "kernel/celltypes.h" #include "kernel/cellaigs.h" #include "kernel/log.h" +#include #include +#include +#include +#include USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -37,6 +41,7 @@ static const FDirection FD_NODIRECTION = 0x0; static const FDirection FD_IN = 0x1; static const FDirection FD_OUT = 0x2; static const FDirection FD_INOUT = 0x3; +static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width // Get a port direction with respect to a specific module. FDirection getPortFDirection(IdString id, Module *module) @@ -91,6 +96,23 @@ const char *make_id(IdString id) return namecache.at(id).c_str(); } +static std::vector Tokenize( const string str, const std::regex regex ) +{ + using namespace std; + + std::vector result; + + sregex_token_iterator it( str.begin(), str.end(), regex, -1 ); + sregex_token_iterator reg_end; + + for ( ; it != reg_end; ++it ) { + if ( !it->str().empty() ) //token could be empty:check + result.emplace_back( it->str() ); + } + + return result; +} + struct FirrtlWorker { Module *module; @@ -173,6 +195,26 @@ struct FirrtlWorker void process_instance(RTLIL::Cell *cell, vector &wire_exprs) { std::string cell_type = fid(cell->type); + std::string instanceOf; + // If this is a parameterized module, its parent module is encoded in the cell type + if (cell->type.substr(0, 8) == "$paramod") + { + std::string::iterator it; + for (it = cell_type.begin(); it < cell_type.end(); it++) + { + switch (*it) { + case '\\': /* FALL_THROUGH */ + case '=': /* FALL_THROUGH */ + case '\'': /* FALL_THROUGH */ + case '$': instanceOf.append("_"); break; + default: instanceOf.append(1, *it); break; + } + } + } + else + { + instanceOf = cell_type; + } std::string cell_name = cellname(cell); std::string cell_name_comment; @@ -182,7 +224,13 @@ struct FirrtlWorker cell_name_comment = ""; // Find the module corresponding to this instance. auto instModule = design->module(cell->type); - wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), cell_type.c_str())); + // If there is no instance for this, just return. + if (instModule == NULL) + { + log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str()); + return; + } + wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str())); for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) { if (it->second.size() > 0) { @@ -194,20 +242,20 @@ struct FirrtlWorker std::string source, sink; switch (dir) { case FD_INOUT: - log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", log_id(cell_type), log_signal(it->second)); + log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second)); case FD_OUT: source = firstName; sink = secondName; break; case FD_NODIRECTION: - log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", log_id(cell_type), log_signal(it->second)); + log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second)); /* FALL_THROUGH */ case FD_IN: source = secondName; sink = firstName; break; default: - log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", log_id(cell_type), log_signal(it->second), dir); + log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir); break; } wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sink.c_str(), source.c_str())); @@ -217,6 +265,20 @@ struct FirrtlWorker } + // Given an expression for a shift amount, and a maximum width, + // generate the FIRRTL expression for equivalent dynamic shift taking into account FIRRTL shift semantics. + std::string gen_dshl(const string b_expr, const int b_padded_width) + { + string result = b_expr; + if (b_padded_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) { + int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1; + string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<name)); @@ -225,6 +287,12 @@ struct FirrtlWorker for (auto wire : module->wires()) { const auto wireName = make_id(wire->name); + // If a wire has initial data, issue a warning since FIRRTL doesn't currently support it. + if (wire->attributes.count("\\init")) { + log_warning("Initial value (%s) for (%s.%s) not supported\n", + wire->attributes.at("\\init").as_string().c_str(), + log_id(module), log_id(wire)); + } if (wire->port_id) { if (wire->port_input && wire->port_output) @@ -240,7 +308,8 @@ struct FirrtlWorker for (auto cell : module->cells()) { - // Is this cell is a module instance? + bool extract_y_bits = false; // Assume no extraction of final bits will be required. + // Is this cell is a module instance? if (cell->type[0] != '$') { process_instance(cell, wire_exprs); @@ -264,21 +333,21 @@ struct FirrtlWorker } string primop; - bool always_uint = false; + bool always_uint = false; if (cell->type == "$not") primop = "not"; - if (cell->type == "$neg") primop = "neg"; - if (cell->type == "$logic_not") { + else if (cell->type == "$neg") primop = "neg"; + else if (cell->type == "$logic_not") { primop = "eq"; a_expr = stringf("%s, UInt(0)", a_expr.c_str()); } - if (cell->type == "$reduce_and") primop = "andr"; - if (cell->type == "$reduce_or") primop = "orr"; - if (cell->type == "$reduce_xor") primop = "xorr"; - if (cell->type == "$reduce_xnor") { + else if (cell->type == "$reduce_and") primop = "andr"; + else if (cell->type == "$reduce_or") primop = "orr"; + else if (cell->type == "$reduce_xor") primop = "xorr"; + else if (cell->type == "$reduce_xnor") { primop = "not"; a_expr = stringf("xorr(%s)", a_expr.c_str()); } - if (cell->type == "$reduce_bool") { + else if (cell->type == "$reduce_bool") { primop = "neq"; // Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand. bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool(); @@ -297,14 +366,16 @@ struct FirrtlWorker continue; } if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$and", "$or", "$eq", "$eqx", - "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl", - "$logic_and", "$logic_or")) + "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl", + "$logic_and", "$logic_or")) { string y_id = make_id(cell->name); bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool(); int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); string a_expr = make_expr(cell->getPort("\\A")); + int a_padded_width = cell->parameters.at("\\A_WIDTH").as_int(); string b_expr = make_expr(cell->getPort("\\B")); + int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int(); wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); if (cell->parameters.at("\\A_SIGNED").as_bool()) { @@ -315,67 +386,93 @@ struct FirrtlWorker if (cell->parameters.at("\\B_SIGNED").as_bool()) { b_expr = "asSInt(" + b_expr + ")"; } - b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); + if (b_padded_width < y_width) { + auto b_sig = cell->getPort("\\B"); + b_padded_width = y_width; + } } - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + auto a_sig = cell->getPort("\\A"); if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type == "$shr")) { a_expr = "asUInt(" + a_expr + ")"; } string primop; - bool always_uint = false; + bool always_uint = false; if (cell->type == "$add") primop = "add"; - if (cell->type == "$sub") primop = "sub"; - if (cell->type == "$mul") primop = "mul"; - if (cell->type == "$div") primop = "div"; - if (cell->type == "$mod") primop = "rem"; - if (cell->type == "$and") { + else if (cell->type == "$sub") primop = "sub"; + else if (cell->type == "$mul") primop = "mul"; + else if (cell->type == "$div") primop = "div"; + else if (cell->type == "$mod") primop = "rem"; + else if (cell->type == "$and") { primop = "and"; always_uint = true; } - if (cell->type == "$or" ) { + else if (cell->type == "$or" ) { primop = "or"; always_uint = true; } - if (cell->type == "$xor") { + else if (cell->type == "$xor") { primop = "xor"; always_uint = true; } - if ((cell->type == "$eq") | (cell->type == "$eqx")) { + else if ((cell->type == "$eq") | (cell->type == "$eqx")) { primop = "eq"; always_uint = true; } - if ((cell->type == "$ne") | (cell->type == "$nex")) { + else if ((cell->type == "$ne") | (cell->type == "$nex")) { primop = "neq"; always_uint = true; } - if (cell->type == "$gt") { + else if (cell->type == "$gt") { primop = "gt"; always_uint = true; } - if (cell->type == "$ge") { + else if (cell->type == "$ge") { primop = "geq"; always_uint = true; } - if (cell->type == "$lt") { + else if (cell->type == "$lt") { primop = "lt"; always_uint = true; } - if (cell->type == "$le") { + else if (cell->type == "$le") { primop = "leq"; always_uint = true; } - if ((cell->type == "$shl") | (cell->type == "$sshl")) primop = "dshl"; - if ((cell->type == "$shr") | (cell->type == "$sshr")) primop = "dshr"; - if ((cell->type == "$logic_and")) { + else if ((cell->type == "$shl") | (cell->type == "$sshl")) { + // FIRRTL will widen the result (y) by the amount of the shift. + // We'll need to offset this by extracting the un-widened portion as Verilog would do. + extract_y_bits = true; + // Is the shift amount constant? + auto b_sig = cell->getPort("\\B"); + if (b_sig.is_fully_const()) { + primop = "shl"; + } else { + primop = "dshl"; + // Convert from FIRRTL left shift semantics. + b_expr = gen_dshl(b_expr, b_padded_width); + } + } + else if ((cell->type == "$shr") | (cell->type == "$sshr")) { + // We don't need to extract a specific range of bits. + extract_y_bits = false; + // Is the shift amount constant? + auto b_sig = cell->getPort("\\B"); + if (b_sig.is_fully_const()) { + primop = "shr"; + } else { + primop = "dshr"; + } + } + else if ((cell->type == "$logic_and")) { primop = "and"; a_expr = "neq(" + a_expr + ", UInt(0))"; b_expr = "neq(" + b_expr + ", UInt(0))"; always_uint = true; } - if ((cell->type == "$logic_or")) { + else if ((cell->type == "$logic_or")) { primop = "or"; a_expr = "neq(" + a_expr + ", UInt(0))"; b_expr = "neq(" + b_expr + ", UInt(0))"; @@ -388,6 +485,11 @@ struct FirrtlWorker string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str()); + // Deal with FIRRTL's "shift widens" semantics + if (extract_y_bits) { + expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1); + } + if ((is_signed && !always_uint) || cell->type.in("$sub")) expr = stringf("asUInt(%s)", expr.c_str()); @@ -513,7 +615,67 @@ struct FirrtlWorker continue; } - log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell)); + // This may be a parameterized module - paramod. + if (cell->type.substr(0, 8) == "$paramod") + { + auto paramod_module = log_id(module); + auto paramod_instance = log_id(cell); + process_instance(cell, wire_exprs); + continue; + } + if (cell->type == "$shiftx") { + // assign y = a[b +: y_width]; + // We'll extract the correct bits as part of the primop. + + string y_id = make_id(cell->name); + int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); + string a_expr = make_expr(cell->getPort("\\A")); + // Get the initial bit selector + string b_expr = make_expr(cell->getPort("\\B")); + wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); + + if (cell->getParam("\\B_SIGNED").as_bool()) { + // Use validif to constrain the selection (test the sign bit) + auto b_string = b_expr.c_str(); + int b_sign = cell->parameters.at("\\B_WIDTH").as_int() - 1; + b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string); + } + string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str()); + + cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); + register_reverse_wire_map(y_id, cell->getPort("\\Y")); + continue; + } + if (cell->type == "$shift") { + // assign y = a >> b; + // where b may be negative + + string y_id = make_id(cell->name); + int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); + string a_expr = make_expr(cell->getPort("\\A")); + string b_expr = make_expr(cell->getPort("\\B")); + auto b_string = b_expr.c_str(); + int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int(); + string expr; + wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); + + if (cell->getParam("\\B_SIGNED").as_bool()) { + // We generate a left or right shift based on the sign of b. + std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_padded_width).c_str(), y_width); + std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string); + expr = stringf("mux(%s < 0, %s, %s)", + b_string, + dshl.c_str(), + dshr.c_str() + ); + } else { + expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string); + } + cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); + register_reverse_wire_map(y_id, cell->getPort("\\Y")); + continue; + } + log_warning("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell)); } for (auto conn : module->connections()) @@ -629,38 +791,53 @@ struct FirrtlBackend : public Backend { log(" write_firrtl [options] [filename]\n"); log("\n"); log("Write a FIRRTL netlist of the current design.\n"); + log("The following commands are executed by this command:\n"); + log(" pmuxtree\n"); log("\n"); } void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE { - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - // if (args[argidx] == "-aig") { - // aig_mode = true; - // continue; - // } - break; + size_t argidx = args.size(); // We aren't expecting any arguments. + + // If we weren't explicitly passed a filename, use the last argument (if it isn't a flag). + if (filename == "") { + if (argidx > 0 && args[argidx - 1][0] != '-') { + // extra_args and friends need to see this argument. + argidx -= 1; + filename = args[argidx]; + } } extra_args(f, filename, args, argidx); + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + log_header(design, "Executing FIRRTL backend.\n"); + log_push(); - Module *top = design->top_module(); - - if (top == nullptr) - log_error("No top module found!\n"); + Pass::call(design, stringf("pmuxtree")); namecache.clear(); autoid_counter = 0; + // Get the top module, or a reasonable facsimile - we need something for the circuit name. + Module *top = design->top_module(); + Module *last = nullptr; + // Generate module and wire names. for (auto module : design->modules()) { make_id(module->name); + last = module; + if (top == nullptr && module->get_bool_attribute("\\top")) { + top = module; + } for (auto wire : module->wires()) if (wire->port_id) make_id(wire->name); } + if (top == nullptr) + top = last; + *f << stringf("circuit %s:\n", make_id(top->name)); for (auto module : design->modules()) diff --git a/tests/asicworld/xfirrtl b/tests/asicworld/xfirrtl new file mode 100644 index 000000000..c782a2bd6 --- /dev/null +++ b/tests/asicworld/xfirrtl @@ -0,0 +1,24 @@ +# This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures. +code_hdl_models_arbiter.v error: reg rst; cannot be driven by primitives or continuous assignment. +code_hdl_models_clk_div_45.v yosys issue: 2nd PMUXTREE pass yields: ERROR: Negative edge clock on FF clk_div_45.$procdff$49. +code_hdl_models_d_ff_gates.v combinational loop +code_hdl_models_d_latch_gates.v combinational loop +code_hdl_models_dff_async_reset.v $adff +code_hdl_models_tff_async_reset.v $adff +code_hdl_models_uart.v $adff +code_specman_switch_fabric.v subfield assignment (bits() <= ...) +code_tidbits_asyn_reset.v $adff +code_tidbits_reg_seq_example.v $adff +code_verilog_tutorial_always_example.v empty module +code_verilog_tutorial_escape_id.v make_id issues (name begins with a digit) +code_verilog_tutorial_explicit.v firrtl backend bug (empty module) +code_verilog_tutorial_first_counter.v error: reg rst; cannot be driven by primitives or continuous assignment. +code_verilog_tutorial_fsm_full.v error: reg reset; cannot be driven by primitives or continuous assignment. +code_verilog_tutorial_if_else.v empty module (everything is under 'always @ (posedge clk)') +[code_verilog_tutorial_n_out_primitive.v empty module +code_verilog_tutorial_parallel_if.v empty module (everything is under 'always @ (posedge clk)') +code_verilog_tutorial_simple_function.v empty module (no hardware) +code_verilog_tutorial_simple_if.v empty module (everything is under 'always @ (posedge clk)') +code_verilog_tutorial_task_global.v empty module (everything is under 'always @ (posedge clk)') +code_verilog_tutorial_v2k_reg.v empty module +code_verilog_tutorial_which_clock.v $adff diff --git a/tests/simple/xfirrtl b/tests/simple/xfirrtl new file mode 100644 index 000000000..00e89b389 --- /dev/null +++ b/tests/simple/xfirrtl @@ -0,0 +1,26 @@ +# This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures. +arraycells.v inst id[0] of +dff_different_styles.v +generate.v combinational loop +hierdefparam.v inst id[0] of +i2c_master_tests.v $adff +macros.v drops modules +mem2reg.v drops modules +mem_arst.v $adff +memory.v $adff +multiplier.v inst id[0] of +muxtree.v drops modules +omsp_dbg_uart.v $adff +operators.v $pow +paramods.v subfield assignment (bits() <= ...) +partsel.v drops modules +process.v drops modules +realexpr.v drops modules +scopes.v original verilog issues ( -x where x isn't declared signed) +sincos.v $adff +specify.v no code (empty module generates error +subbytes.v $adff +task_func.v drops modules +values.v combinational loop +vloghammer.v combinational loop +wreduce.v original verilog issues ( -x where x isn't declared signed) diff --git a/tests/tools/autotest.mk b/tests/tools/autotest.mk index c68678929..e0f2bcdc1 100644 --- a/tests/tools/autotest.mk +++ b/tests/tools/autotest.mk @@ -1,7 +1,7 @@ -EXTRA_FLAGS= -SEED= - +# Don't bother defining default values for SEED and EXTRA_FLAGS. +# Their "natural" default values should be sufficient, +# and they may be overridden in the environment. ifneq ($(strip $(SEED)),) SEEDOPT=-S$(SEED) endif diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index d6216244f..218edf931 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -17,12 +17,18 @@ scriptfiles="" scriptopt="" toolsdir="$(cd $(dirname $0); pwd)" warn_iverilog_git=false +# The following are used in verilog to firrtl regression tests. +# Typically these will be passed as environment variables: +#EXTRA_FLAGS="--firrtl2verilog 'java -cp /.../firrtl/utils/bin/firrtl.jar firrtl.Driver'" +# The tests are skipped if firrtl2verilog is the empty string (the default). +firrtl2verilog="" +xfirrtl="../xfirrtl" if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdata ]; then ( set -ex; ${CC:-gcc} -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1 fi -while getopts xmGl:wkjvref:s:p:n:S:I: opt; do +while getopts xmGl:wkjvref:s:p:n:S:I:-: opt; do case "$opt" in x) use_xsim=true ;; @@ -59,8 +65,24 @@ while getopts xmGl:wkjvref:s:p:n:S:I: opt; do include_opts="$include_opts -I $OPTARG" xinclude_opts="$xinclude_opts -i $OPTARG" minclude_opts="$minclude_opts +incdir+$OPTARG" ;; + -) + case "${OPTARG}" in + xfirrtl) + xfirrtl="${!OPTIND}" + OPTIND=$(( $OPTIND + 1 )) + ;; + firrtl2verilog) + firrtl2verilog="${!OPTIND}" + OPTIND=$(( $OPTIND + 1 )) + ;; + *) + if [ "$OPTERR" == 1 ] && [ "${optspec:0:1}" != ":" ]; then + echo "Unknown option --${OPTARG}" >&2 + fi + ;; + esac;; *) - echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] verilog-files\n" >&2 + echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] [--xfirrtl FIRRTL test exclude file] [--firrtl2verilog command to generate verilog from firrtl] verilog-files\n" >&2 exit 1 esac done @@ -109,6 +131,8 @@ do fn=$(basename $fn) bn=$(basename $bn) + rm -f ${bn}_ref.fir + egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.v if [ ! -f ../${bn}_tb.v ]; then @@ -148,6 +172,13 @@ do else test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.v test_passes -f "$frontend $include_opts" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" ${bn}_ref.v + if [ -n "$firrtl2verilog" ]; then + if test -z "$xfirrtl" || ! grep "$fn" "$xfirrtl" ; then + "$toolsdir"/../../yosys -b "firrtl" -o ${bn}_ref.fir -f "$frontend $include_opts" -p "prep -nordff; proc; opt; memory; opt; fsm; opt -full -fine; pmuxtree" ${bn}_ref.v + $firrtl2verilog -i ${bn}_ref.fir -o ${bn}_ref.fir.v -X verilog + test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.fir.v + fi + fi fi touch ../${bn}.log } @@ -160,14 +191,18 @@ do ( set -ex; body; ) > ${bn}.err 2>&1 fi + did_firrtl="" + if [ -f ${bn}.out/${bn}_ref.fir ]; then + did_firrtl="+FIRRTL " + fi if [ -f ${bn}.log ]; then mv ${bn}.err ${bn}.log - echo "${status_prefix}-> ok" + echo "${status_prefix}${did_firrtl}-> ok" elif [ -f ${bn}.skip ]; then mv ${bn}.err ${bn}.skip echo "${status_prefix}-> skip" else - echo "${status_prefix}-> ERROR!" + echo "${status_prefix}${did_firrtl}-> ERROR!" if $warn_iverilog_git; then echo "Note: Make sure that 'iverilog' is an up-to-date git checkout of Icarus Verilog." fi From 5c504c5ae676488f7e0b53f827f189fa7cacb2c8 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Fri, 15 Feb 2019 11:31:37 -0800 Subject: [PATCH 22/53] Define basic_cell_type() function and use it to derive the cell type for array references (instead of duplicating the code). --- passes/hierarchy/hierarchy.cc | 50 ++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 0e28dbca2..332ebdfbb 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -140,6 +140,23 @@ void generate(RTLIL::Design *design, const std::vector &celltypes, } } +// Return the "basic" type for an array item. +std::string basic_cell_type(const std::string celltype, int pos[3] = nullptr) { + std::string basicType = celltype; + if (celltype.substr(0, 7) == "$array:") { + int pos_idx = celltype.find_first_of(':'); + int pos_num = celltype.find_first_of(':', pos_idx + 1); + int pos_type = celltype.find_first_of(':', pos_num + 1); + basicType = celltype.substr(pos_type + 1); + if (pos != nullptr) { + pos[0] = pos_idx; + pos[1] = pos_num; + pos[2] = pos_type; + } + } + return basicType; +} + bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, std::vector &libdirs) { bool did_something = false; @@ -178,9 +195,11 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check std::vector connections_to_add_signal; if (cell->type.substr(0, 7) == "$array:") { - int pos_idx = cell->type.str().find_first_of(':'); - int pos_num = cell->type.str().find_first_of(':', pos_idx + 1); - int pos_type = cell->type.str().find_first_of(':', pos_num + 1); + int pos[3]; + basic_cell_type(cell->type.str(), pos); + int pos_idx = pos[0]; + int pos_num = pos[1]; + int pos_type = pos[2]; int idx = atoi(cell->type.str().substr(pos_idx + 1, pos_num).c_str()); int num = atoi(cell->type.str().substr(pos_num + 1, pos_type).c_str()); array_cells[cell] = std::pair(idx, num); @@ -439,10 +458,7 @@ void hierarchy_worker(RTLIL::Design *design, std::setcells()) { std::string celltype = cell->type.str(); if (celltype.substr(0, 7) == "$array:") { - int pos_idx = celltype.find_first_of(':'); - int pos_num = celltype.find_first_of(':', pos_idx + 1); - int pos_type = celltype.find_first_of(':', pos_num + 1); - celltype = celltype.substr(pos_type + 1); + celltype = basic_cell_type(celltype); } if (design->module(celltype)) hierarchy_worker(design, used, design->module(celltype), indent+4); @@ -502,9 +518,23 @@ int find_top_mod_score(Design *design, Module *module, dict &db) if (db.count(module) == 0) { int score = 0; db[module] = 0; - for (auto cell : module->cells()) - if (design->module(cell->type)) - score = max(score, find_top_mod_score(design, design->module(cell->type), db) + 1); + for (auto cell : module->cells()) { + std::string celltype = cell->type.str(); + // Is this an array instance + if (celltype.substr(0, 7) == "$array:") { + celltype = basic_cell_type(celltype); + // Is this cell is a module instance? + if (celltype[0] != '$') { + auto instModule = design->module(celltype); + // If there is no instance for this, issue a warning. + if (instModule == NULL) { + log_warning("find_top_mod_score: no instance for %s.%s\n", celltype.c_str(), cell->name.c_str()); + } + if (instModule != NULL) + score = max(score, find_top_mod_score(design, instModule, db) + 1); + } + } + } db[module] = score; } return db.at(module); From 34153adef408bc226430f05d14cd4af9384359f9 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Fri, 15 Feb 2019 11:56:51 -0800 Subject: [PATCH 23/53] Append (instead of over-writing) EXTRA_FLAGS --- tests/asicworld/run-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/asicworld/run-test.sh b/tests/asicworld/run-test.sh index d5708c456..c22ab6928 100755 --- a/tests/asicworld/run-test.sh +++ b/tests/asicworld/run-test.sh @@ -11,4 +11,4 @@ do done shift "$((OPTIND-1))" -exec ${MAKE:-make} -f ../tools/autotest.mk $seed EXTRA_FLAGS="-e" *.v +exec ${MAKE:-make} -f ../tools/autotest.mk $seed EXTRA_FLAGS+="-e" *.v From c245041bfe2ee0d5b5504fa5e9459ac52e836c33 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Fri, 15 Feb 2019 12:00:28 -0800 Subject: [PATCH 24/53] Removed unused variables, functions. --- backends/firrtl/firrtl.cc | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index 7ca5dc756..0917ecba6 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -96,23 +96,6 @@ const char *make_id(IdString id) return namecache.at(id).c_str(); } -static std::vector Tokenize( const string str, const std::regex regex ) -{ - using namespace std; - - std::vector result; - - sregex_token_iterator it( str.begin(), str.end(), regex, -1 ); - sregex_token_iterator reg_end; - - for ( ; it != reg_end; ++it ) { - if ( !it->str().empty() ) //token could be empty:check - result.emplace_back( it->str() ); - } - - return result; -} - struct FirrtlWorker { Module *module; @@ -373,7 +356,6 @@ struct FirrtlWorker bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool(); int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); string a_expr = make_expr(cell->getPort("\\A")); - int a_padded_width = cell->parameters.at("\\A_WIDTH").as_int(); string b_expr = make_expr(cell->getPort("\\B")); int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int(); wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); @@ -618,8 +600,6 @@ struct FirrtlWorker // This may be a parameterized module - paramod. if (cell->type.substr(0, 8) == "$paramod") { - auto paramod_module = log_id(module); - auto paramod_instance = log_id(cell); process_instance(cell, wire_exprs); continue; } From 5a853ed46cd3a41df9da4c8206f9416748788487 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 17 Feb 2019 15:35:48 +0100 Subject: [PATCH 25/53] Add actual DSP inference to ice40_dsp pass Signed-off-by: Clifford Wolf --- passes/pmgen/ice40_dsp.cc | 197 +++++++++++++++++++++++++++++++++---- passes/pmgen/ice40_dsp.pmg | 18 +++- passes/pmgen/pmgen.py | 23 ++++- 3 files changed, 214 insertions(+), 24 deletions(-) diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 78b5bad33..7463d598f 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -24,6 +24,180 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +void create_ice40_dsp(ice40_dsp_pm &pm) +{ +#if 0 + log("\n"); + log("ffA: %s\n", log_id(pm.st.ffA, "--")); + log("ffB: %s\n", log_id(pm.st.ffB, "--")); + log("mul: %s\n", log_id(pm.st.mul, "--")); + log("ffY: %s\n", log_id(pm.st.ffY, "--")); + log("addAB: %s\n", log_id(pm.st.addAB, "--")); + log("muxAB: %s\n", log_id(pm.st.muxAB, "--")); + log("ffS: %s\n", log_id(pm.st.ffS, "--")); +#endif + + log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(pm.st.mul)); + + if (GetSize(pm.st.sigA) > 16) { + log(" input A (%s) is too large (%d > 16).\n", log_signal(pm.st.sigA), GetSize(pm.st.sigA)); + return; + } + + if (GetSize(pm.st.sigB) > 16) { + log(" input B (%s) is too large (%d > 16).\n", log_signal(pm.st.sigB), GetSize(pm.st.sigB)); + return; + } + + if (GetSize(pm.st.sigS) > 32) { + log(" accumulator (%s) is too large (%d > 32).\n", log_signal(pm.st.sigS), GetSize(pm.st.sigS)); + return; + } + + if (GetSize(pm.st.sigY) > 32) { + log(" output (%s) is too large (%d > 32).\n", log_signal(pm.st.sigY), GetSize(pm.st.sigY)); + return; + } + + log(" replacing $mul with SB_MAC16 cell.\n"); + + bool mul_signed = pm.st.mul->getParam("\\A_SIGNED").as_bool(); + + Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); + pm.module->swap_names(cell, pm.st.mul); + + // SB_MAC16 Input Interface + + SigSpec A = pm.st.sigA; + A.extend_u0(16, mul_signed); + + SigSpec B = pm.st.sigB; + B.extend_u0(16, mul_signed); + + SigSpec CD; + if (pm.st.muxA) + CD = pm.st.muxA->getPort("\\B"); + if (pm.st.muxB) + CD = pm.st.muxB->getPort("\\A"); + CD.extend_u0(32, mul_signed); + + cell->setPort("\\A", A); + cell->setPort("\\B", B); + cell->setPort("\\C", CD.extract(0, 16)); + cell->setPort("\\D", CD.extract(16, 16)); + + cell->setParam("\\A_REG", pm.st.ffA ? State::S0 : State::S1); + cell->setParam("\\B_REG", pm.st.ffB ? State::S0 : State::S1); + + cell->setPort("\\AHOLD", State::S0); + cell->setPort("\\BHOLD", State::S0); + cell->setPort("\\CHOLD", State::S0); + cell->setPort("\\DHOLD", State::S0); + + cell->setPort("\\IRSTTOP", State::S0); + cell->setPort("\\IRSTBOT", State::S0); + + if (pm.st.clock_vld) + { + cell->setPort("\\CLK", pm.st.clock); + cell->setPort("\\CE", State::S1); + cell->setParam("\\NEG_TRIGGER", pm.st.clock_pol ? State::S0 : State::S1); + + log(" clock: %s (%s)", log_signal(pm.st.clock), pm.st.clock_pol ? "posedge" : "negedge"); + + if (pm.st.ffA) + log(" ffA:%s", log_id(pm.st.ffA)); + + if (pm.st.ffB) + log(" ffB:%s", log_id(pm.st.ffB)); + + if (pm.st.ffY) + log(" ffY:%s", log_id(pm.st.ffY)); + + if (pm.st.ffS) + log(" ffS:%s", log_id(pm.st.ffS)); + + log("\n"); + } + else + { + cell->setPort("\\CLK", State::S0); + cell->setPort("\\CE", State::S0); + cell->setParam("\\NEG_TRIGGER", State::S0); + } + + // SB_MAC16 Cascade Interface + + cell->setPort("\\SIGNEXTIN", State::Sx); + cell->setPort("\\SIGNEXTOUT", pm.module->addWire(NEW_ID)); + + cell->setPort("\\CI", State::Sx); + cell->setPort("\\CO", pm.module->addWire(NEW_ID)); + + cell->setPort("\\ACCUMCI", State::Sx); + cell->setPort("\\ACCUMCO", pm.module->addWire(NEW_ID)); + + // SB_MAC16 Output Interface + + SigSpec O = pm.st.ffS ? pm.st.sigS : pm.st.sigY; + if (GetSize(O) < 32) + O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); + + cell->setPort("\\O", O); + + if (pm.st.addAB) { + log(" accumulator %s (%s)\n", log_id(pm.st.addAB), log_id(pm.st.addAB->type)); + cell->setPort("\\ADDSUBTOP", pm.st.addAB->type == "$add" ? State::S0 : State::S1); + cell->setPort("\\ADDSUBBOT", pm.st.addAB->type == "$add" ? State::S0 : State::S1); + } else { + cell->setPort("\\ADDSUBTOP", State::S0); + cell->setPort("\\ADDSUBBOT", State::S0); + } + + cell->setPort("\\ORTSTOP", State::S0); + cell->setPort("\\ORTSBOT", State::S0); + + cell->setPort("\\OHOLDTOP", State::S0); + cell->setPort("\\OHOLDBOT", State::S0); + + SigSpec acc_reset = State::S0; + if (pm.st.muxA) + acc_reset = pm.st.muxA->getPort("\\S"); + if (pm.st.muxB) + acc_reset = pm.module->Not(NEW_ID, pm.st.muxB->getPort("\\S")); + + cell->setPort("\\OLOADTOP", acc_reset); + cell->setPort("\\OLOADBOT", acc_reset); + + // SB_MAC16 Remaining Parameters + + cell->setParam("\\C_REG", State::S0); + cell->setParam("\\D_REG", State::S0); + + cell->setParam("\\TOP_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0); + cell->setParam("\\BOT_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0); + cell->setParam("\\PIPELINE_16X16_MULT_REG1", pm.st.ffY ? State::S1 : State::S0); + cell->setParam("\\PIPELINE_16X16_MULT_REG2", State::S0); + + cell->setParam("\\TOPOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2)); + cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); + cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0); + cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2)); + + cell->setParam("\\BOTOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2)); + cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2)); + cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0); + cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); + + cell->setParam("\\MODE_8x8", State::S0); + cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0); + cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0); + + pm.autoremove(pm.st.mul); + pm.autoremove(pm.st.ffY); + pm.autoremove(pm.st.ffS); +} + struct Ice40DspPass : public Pass { Ice40DspPass() : Pass("ice40_dsp", "iCE40: map multipliers") { } void help() YS_OVERRIDE @@ -32,7 +206,7 @@ struct Ice40DspPass : public Pass { log("\n"); log(" ice40_dsp [options] [selection]\n"); log("\n"); - log("Map multipliers and iCE40 DSP resources.\n"); + log("Map multipliers and multiply-accumulate blocks to iCE40 DSP resources.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -51,26 +225,7 @@ struct Ice40DspPass : public Pass { extra_args(args, argidx, design); for (auto module : design->selected_modules()) - { - ice40_dsp_pm pm(module, module->selected_cells()); - pm.run([&]() - { - log("\n"); - log("ffA: %s\n", log_id(pm.st.ffA, "--")); - log("ffB: %s\n", log_id(pm.st.ffB, "--")); - log("mul: %s\n", log_id(pm.st.mul, "--")); - log("ffY: %s\n", log_id(pm.st.ffY, "--")); - log("addAB: %s\n", log_id(pm.st.addAB, "--")); - log("muxAB: %s\n", log_id(pm.st.muxAB, "--")); - log("ffS: %s\n", log_id(pm.st.ffS, "--")); - - pm.blacklist(pm.st.mul); - pm.blacklist(pm.st.ffA); - pm.blacklist(pm.st.ffB); - pm.blacklist(pm.st.ffY); - pm.blacklist(pm.st.ffS); - }); - } + ice40_dsp_pm(module, module->selected_cells()).run(create_ice40_dsp); } } Ice40DspPass; diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 1370cb66a..58e1ce0e0 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -63,7 +63,7 @@ code sigY clock clock_pol clock_vld sigY = port(mul, \Y); if (ffY) { - sigY = port(ffY, \D); + sigY = port(ffY, \Q); SigBit c = port(ffY, \CLK).as_bit(); bool cp = param(ffY, \CLK_POLARITY).as_bool(); @@ -77,7 +77,7 @@ code sigY clock clock_pol clock_vld endcode match addA - select addA->type.in($add, $sub) + select addA->type.in($add) select nusers(port(addA, \A)) == 2 index port(addA, \A) === sigY optional @@ -134,3 +134,17 @@ match ffS index port(ffS, \D) === port(muxAB, \Y) index port(ffS, \Q) === sigS endmatch + +code clock clock_pol clock_vld + if (ffS) { + SigBit c = port(ffS, \CLK).as_bit(); + bool cp = param(ffS, \CLK_POLARITY).as_bool(); + + if (clock_vld && (c != clock || cp != clock_pol)) + reject; + + clock = c; + clock_pol = cp; + clock_vld = true; + } +endcode diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index a59cf5a81..e688a4567 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -203,6 +203,7 @@ with open("%s_pm.h" % prefix, "w") as f: print(" dict> index_{};".format(index, index), file=f) print(" dict> sigusers;", file=f) print(" pool blacklist_cells;", file=f) + print(" pool autoremove_cells;", file=f) print(" bool blacklist_dirty;", file=f) print(" int rollback;", file=f) print("", file=f) @@ -244,6 +245,15 @@ with open("%s_pm.h" % prefix, "w") as f: print(" }", file=f) print("", file=f) + print(" void autoremove(Cell *cell) {", file=f) + print(" if (cell != nullptr) {", file=f) + print(" if (blacklist_cells.insert(cell).second)", file=f) + print(" blacklist_dirty = true;", file=f) + print(" autoremove_cells.insert(cell);", file=f) + print(" }", file=f) + print(" }", file=f) + print("", file=f) + print(" void check_blacklist() {", file=f) print(" if (!blacklist_dirty)", file=f) print(" return;", file=f) @@ -308,7 +318,13 @@ with open("%s_pm.h" % prefix, "w") as f: print(" }", file=f) print("", file=f) - print(" void run(std::function on_accept_f) {{".format(prefix), file=f) + print(" ~{}_pm() {{".format(prefix), file=f) + print(" for (auto cell : autoremove_cells)", file=f) + print(" module->remove(cell);", file=f) + print(" }", file=f) + print("", file=f) + + print(" void run(std::function on_accept_f) {", file=f) print(" on_accept = on_accept_f;", file=f) print(" rollback = 0;", file=f) print(" blacklist_dirty = false;", file=f) @@ -321,6 +337,11 @@ with open("%s_pm.h" % prefix, "w") as f: print(" }", file=f) print("", file=f) + print(" void run(std::function on_accept_f) {{".format(prefix), file=f) + print(" run([&](){on_accept_f(*this);});", file=f) + print(" }", file=f) + print("", file=f) + for index in range(len(blocks)): block = blocks[index] From 3d3353e02005883af916b1b1da2c670a29060169 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 17 Feb 2019 12:11:52 -0800 Subject: [PATCH 26/53] Revert "Add INIT parameter to all ff/latch cells" This reverts commit 742b4e01b498ae2e735d40565f43607d69a015d8. --- techlibs/common/simcells.v | 111 +++++++++++++------------------------ techlibs/common/simlib.v | 18 ++---- 2 files changed, 43 insertions(+), 86 deletions(-) diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v index b9957bd5e..289673e82 100644 --- a/techlibs/common/simcells.v +++ b/techlibs/common/simcells.v @@ -451,9 +451,8 @@ endmodule //- 1 1 | y //- module \$_SR_NN_ (S, R, Q); -parameter INIT = 1'bx; input S, R; -output reg Q = INIT; +output reg Q; always @(negedge S, negedge R) begin if (R == 0) Q <= 0; @@ -476,9 +475,8 @@ endmodule //- 1 0 | y //- module \$_SR_NP_ (S, R, Q); -parameter INIT = 1'bx; input S, R; -output reg Q = INIT; +output reg Q; always @(negedge S, posedge R) begin if (R == 1) Q <= 0; @@ -501,9 +499,8 @@ endmodule //- 0 1 | y //- module \$_SR_PN_ (S, R, Q); -parameter INIT = 1'bx; input S, R; -output reg Q = INIT; +output reg Q; always @(posedge S, negedge R) begin if (R == 0) Q <= 0; @@ -526,9 +523,8 @@ endmodule //- 0 0 | y //- module \$_SR_PP_ (S, R, Q); -parameter INIT = 1'bx; input S, R; -output reg Q = INIT; +output reg Q; always @(posedge S, posedge R) begin if (R == 1) Q <= 0; @@ -546,9 +542,8 @@ endmodule //- type is usually only used in netlists for formal verification.) //- module \$_FF_ (D, Q); -parameter INIT = 1'bx; input D; -output reg Q = INIT; +output reg Q; always @($global_clock) begin Q <= D; end @@ -567,9 +562,8 @@ endmodule //- - - | q //- module \$_DFF_N_ (D, C, Q); -parameter INIT = 1'bx; input D, C; -output reg Q = INIT; +output reg Q; always @(negedge C) begin Q <= D; end @@ -587,9 +581,8 @@ endmodule //- - - | q //- module \$_DFF_P_ (D, C, Q); -parameter INIT = 1'bx; input D, C; -output reg Q = INIT; +output reg Q; always @(posedge C) begin Q <= D; end @@ -607,9 +600,8 @@ endmodule //- - - - | q //- module \$_DFFE_NN_ (D, C, E, Q); -parameter INIT = 1'bx; input D, C, E; -output reg Q = INIT; +output reg Q; always @(negedge C) begin if (!E) Q <= D; end @@ -627,9 +619,8 @@ endmodule //- - - - | q //- module \$_DFFE_NP_ (D, C, E, Q); -parameter INIT = 1'bx; input D, C, E; -output reg Q = INIT; +output reg Q; always @(negedge C) begin if (E) Q <= D; end @@ -647,9 +638,8 @@ endmodule //- - - - | q //- module \$_DFFE_PN_ (D, C, E, Q); -parameter INIT = 1'bx; input D, C, E; -output reg Q = INIT; +output reg Q; always @(posedge C) begin if (!E) Q <= D; end @@ -667,9 +657,8 @@ endmodule //- - - - | q //- module \$_DFFE_PP_ (D, C, E, Q); -parameter INIT = 1'bx; input D, C, E; -output reg Q = INIT; +output reg Q; always @(posedge C) begin if (E) Q <= D; end @@ -688,9 +677,8 @@ endmodule //- - - - | q //- module \$_DFF_NN0_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(negedge C or negedge R) begin if (R == 0) Q <= 0; @@ -712,9 +700,8 @@ endmodule //- - - - | q //- module \$_DFF_NN1_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(negedge C or negedge R) begin if (R == 0) Q <= 1; @@ -736,9 +723,8 @@ endmodule //- - - - | q //- module \$_DFF_NP0_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(negedge C or posedge R) begin if (R == 1) Q <= 0; @@ -760,9 +746,8 @@ endmodule //- - - - | q //- module \$_DFF_NP1_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(negedge C or posedge R) begin if (R == 1) Q <= 1; @@ -784,9 +769,8 @@ endmodule //- - - - | q //- module \$_DFF_PN0_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(posedge C or negedge R) begin if (R == 0) Q <= 0; @@ -808,9 +792,8 @@ endmodule //- - - - | q //- module \$_DFF_PN1_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(posedge C or negedge R) begin if (R == 0) Q <= 1; @@ -832,9 +815,8 @@ endmodule //- - - - | q //- module \$_DFF_PP0_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(posedge C or posedge R) begin if (R == 1) Q <= 0; @@ -856,9 +838,8 @@ endmodule //- - - - | q //- module \$_DFF_PP1_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(posedge C or posedge R) begin if (R == 1) Q <= 1; @@ -881,9 +862,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_NNN_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(negedge C, negedge S, negedge R) begin if (R == 0) Q <= 0; @@ -909,9 +889,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_NNP_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(negedge C, negedge S, posedge R) begin if (R == 1) Q <= 0; @@ -937,9 +916,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_NPN_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(negedge C, posedge S, negedge R) begin if (R == 0) Q <= 0; @@ -964,9 +942,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_NPP_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(negedge C, posedge S, posedge R) begin if (R == 1) Q <= 0; @@ -991,9 +968,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_PNN_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(posedge C, negedge S, negedge R) begin if (R == 0) Q <= 0; @@ -1019,9 +995,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_PNP_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(posedge C, negedge S, posedge R) begin if (R == 1) Q <= 0; @@ -1047,9 +1022,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_PPN_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(posedge C, posedge S, negedge R) begin if (R == 0) Q <= 0; @@ -1074,9 +1048,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_PPP_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(posedge C, posedge S, posedge R) begin if (R == 1) Q <= 0; @@ -1099,9 +1072,8 @@ endmodule //- - - | q //- module \$_DLATCH_N_ (E, D, Q); -parameter INIT = 1'bx; input E, D; -output reg Q = INIT; +output reg Q; always @* begin if (E == 0) Q <= D; @@ -1120,9 +1092,8 @@ endmodule //- - - | q //- module \$_DLATCH_P_ (E, D, Q); -parameter INIT = 1'bx; input E, D; -output reg Q = INIT; +output reg Q; always @* begin if (E == 1) Q <= D; @@ -1143,9 +1114,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_NNN_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 0) Q <= 0; @@ -1171,9 +1141,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_NNP_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 1) Q <= 0; @@ -1199,9 +1168,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_NPN_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 0) Q <= 0; @@ -1226,9 +1194,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_NPP_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 1) Q <= 0; @@ -1253,9 +1220,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_PNN_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 0) Q <= 0; @@ -1281,9 +1247,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_PNP_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 1) Q <= 0; @@ -1309,9 +1274,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_PPN_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 0) Q <= 0; @@ -1336,9 +1300,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_PPP_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 1) Q <= 0; diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index a1e0c1575..8e43fe058 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1464,11 +1464,10 @@ module \$dff (CLK, D, Q); parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; -parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input CLK; input [WIDTH-1:0] D; -output reg [WIDTH-1:0] Q = INIT; +output reg [WIDTH-1:0] Q; wire pos_clk = CLK == CLK_POLARITY; always @(posedge pos_clk) begin @@ -1484,11 +1483,10 @@ module \$dffe (CLK, EN, D, Q); parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter EN_POLARITY = 1'b1; -parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input CLK, EN; input [WIDTH-1:0] D; -output reg [WIDTH-1:0] Q = INIT; +output reg [WIDTH-1:0] Q; wire pos_clk = CLK == CLK_POLARITY; always @(posedge pos_clk) begin @@ -1506,11 +1504,10 @@ parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter SET_POLARITY = 1'b1; parameter CLR_POLARITY = 1'b1; -parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input CLK; input [WIDTH-1:0] SET, CLR, D; -output reg [WIDTH-1:0] Q = INIT; +output reg [WIDTH-1:0] Q; wire pos_clk = CLK == CLK_POLARITY; wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET; @@ -1540,11 +1537,10 @@ parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter ARST_POLARITY = 1'b1; parameter ARST_VALUE = 0; -parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input CLK, ARST; input [WIDTH-1:0] D; -output reg [WIDTH-1:0] Q = INIT; +output reg [WIDTH-1:0] Q; wire pos_clk = CLK == CLK_POLARITY; wire pos_arst = ARST == ARST_POLARITY; @@ -1563,11 +1559,10 @@ module \$dlatch (EN, D, Q); parameter WIDTH = 0; parameter EN_POLARITY = 1'b1; -parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input EN; input [WIDTH-1:0] D; -output reg [WIDTH-1:0] Q = INIT; +output reg [WIDTH-1:0] Q; always @* begin if (EN == EN_POLARITY) @@ -1585,11 +1580,10 @@ parameter WIDTH = 0; parameter EN_POLARITY = 1'b1; parameter SET_POLARITY = 1'b1; parameter CLR_POLARITY = 1'b1; -parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input EN; input [WIDTH-1:0] SET, CLR, D; -output reg [WIDTH-1:0] Q = INIT; +output reg [WIDTH-1:0] Q; wire pos_en = EN == EN_POLARITY; wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET; From 11480b4fa3ba031541e22b52d9ccd658a3e52ff1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 17 Feb 2019 12:18:12 -0800 Subject: [PATCH 27/53] Instead of INIT param on cells, use initial statement with hier ref as per @cliffordwolf --- backends/verilog/verilog_backend.cc | 31 ++++++++++++----------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 4b5a13941..d351a6266 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -293,7 +293,7 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o } } -void dump_reg_init(std::ostream &f, SigSpec sig, bool write_equals = true) +void dump_reg_init(std::ostream &f, SigSpec sig) { Const initval; bool gotinit = false; @@ -308,7 +308,7 @@ void dump_reg_init(std::ostream &f, SigSpec sig, bool write_equals = true) } if (gotinit) { - if (write_equals) f << " = "; + f << " = "; dump_const(f, initval); } } @@ -1250,14 +1250,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) dump_attributes(f, indent, cell->attributes); f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str()); - std::string init; - if (reg_ct.count(cell->type) && cell->hasPort("\\Q")) { - std::stringstream ss; - dump_reg_init(ss, cell->getPort("\\Q"), false /* write_equals */); - init = ss.str(); - } - - if (!defparam && (cell->parameters.size() > 0 || !init.empty())) { + if (!defparam && cell->parameters.size() > 0) { f << stringf(" #("); for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { if (it != cell->parameters.begin()) @@ -1267,11 +1260,6 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) dump_const(f, it->second, -1, 0, false, is_signed); f << stringf(")"); } - if (!init.empty()) { - if (!cell->parameters.empty()) - f << stringf(","); - f << stringf("\n%s .INIT(%s)", indent.c_str(), init.c_str()); - } f << stringf("\n%s" ")", indent.c_str()); } @@ -1313,17 +1301,24 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) } f << stringf("\n%s" ");\n", indent.c_str()); - if (defparam && (cell->parameters.size() > 0 || !init.empty())) { + if (defparam && cell->parameters.size() > 0) { for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str()); bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0; dump_const(f, it->second, -1, 0, false, is_signed); f << stringf(";\n"); } - if (!init.empty()) - f << stringf("%sdefparam %s.INIT = %s;\n", indent.c_str(), cell_name.c_str(), init.c_str()); } + if (reg_ct.count(cell->type) && cell->hasPort("\\Q")) { + std::stringstream ss; + dump_reg_init(ss, cell->getPort("\\Q")); + if (!ss.str().empty()) { + f << stringf("%sinitial %s.Q", indent.c_str(), cell_name.c_str()); + f << ss.str(); + f << ";\n"; + } + } } void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) From 62493c91b24c1775f82e64712bf42b175944fe08 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 19 Feb 2019 13:42:21 +0100 Subject: [PATCH 28/53] Add first draft of functional SB_MAC16 model Signed-off-by: Clifford Wolf --- techlibs/ice40/cells_sim.v | 228 +++++++++++++++++------ techlibs/ice40/tests/test_dsp_model.gtkw | 87 +++++++++ techlibs/ice40/tests/test_dsp_model.sh | 6 + techlibs/ice40/tests/test_dsp_model.v | 199 ++++++++++++++++++++ 4 files changed, 467 insertions(+), 53 deletions(-) create mode 100644 techlibs/ice40/tests/test_dsp_model.gtkw create mode 100644 techlibs/ice40/tests/test_dsp_model.sh create mode 100644 techlibs/ice40/tests/test_dsp_model.v diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 38ed45981..4a92fccdf 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -886,59 +886,6 @@ module SB_WARMBOOT ( ); endmodule -// UltraPlus feature cells -(* blackbox *) -module SB_MAC16 ( - input CLK, - input CE, - input [15:0] C, - input [15:0] A, - input [15:0] B, - input [15:0] D, - input AHOLD, - input BHOLD, - input CHOLD, - input DHOLD, - input IRSTTOP, - input IRSTBOT, - input ORSTTOP, - input ORSTBOT, - input OLOADTOP, - input OLOADBOT, - input ADDSUBTOP, - input ADDSUBBOT, - input OHOLDTOP, - input OHOLDBOT, - input CI, - input ACCUMCI, - input SIGNEXTIN, - output [31:0] O, - output CO, - output ACCUMCO, - output SIGNEXTOUT -); -parameter NEG_TRIGGER = 1'b0; -parameter C_REG = 1'b0; -parameter A_REG = 1'b0; -parameter B_REG = 1'b0; -parameter D_REG = 1'b0; -parameter TOP_8x8_MULT_REG = 1'b0; -parameter BOT_8x8_MULT_REG = 1'b0; -parameter PIPELINE_16x16_MULT_REG1 = 1'b0; -parameter PIPELINE_16x16_MULT_REG2 = 1'b0; -parameter TOPOUTPUT_SELECT = 2'b00; -parameter TOPADDSUB_LOWERINPUT = 2'b00; -parameter TOPADDSUB_UPPERINPUT = 1'b0; -parameter TOPADDSUB_CARRYSELECT = 2'b00; -parameter BOTOUTPUT_SELECT = 2'b00; -parameter BOTADDSUB_LOWERINPUT = 2'b00; -parameter BOTADDSUB_UPPERINPUT = 1'b0; -parameter BOTADDSUB_CARRYSELECT = 2'b00; -parameter MODE_8x8 = 1'b0; -parameter A_SIGNED = 1'b0; -parameter B_SIGNED = 1'b0; -endmodule - module SB_SPRAM256KA ( input [13:0] ADDRESS, input [15:0] DATAIN, @@ -1273,3 +1220,178 @@ module SB_IO_OD ( endgenerate `endif endmodule + +module SB_MAC16 ( + input CLK, CE, + input [15:0] C, A, B, D, + input AHOLD, BHOLD, CHOLD, DHOLD, + input IRSTTOP, IRSTBOT, + input ORSTTOP, ORSTBOT, + input OLOADTOP, OLOADBOT, + input ADDSUBTOP, ADDSUBBOT, + input OHOLDTOP, OHOLDBOT, + input CI, ACCUMCI, SIGNEXTIN, + output [31:0] O, + output CO, ACCUMCO, SIGNEXTOUT +); + parameter [0:0] NEG_TRIGGER = 0; + parameter [0:0] C_REG = 0; + parameter [0:0] A_REG = 0; + parameter [0:0] B_REG = 0; + parameter [0:0] D_REG = 0; + parameter [0:0] TOP_8x8_MULT_REG = 0; + parameter [0:0] BOT_8x8_MULT_REG = 0; + parameter [0:0] PIPELINE_16x16_MULT_REG1 = 0; + parameter [0:0] PIPELINE_16x16_MULT_REG2 = 0; + parameter [1:0] TOPOUTPUT_SELECT = 0; + parameter [1:0] TOPADDSUB_LOWERINPUT = 0; + parameter [0:0] TOPADDSUB_UPPERINPUT = 0; + parameter [1:0] TOPADDSUB_CARRYSELECT = 0; + parameter [1:0] BOTOUTPUT_SELECT = 0; + parameter [1:0] BOTADDSUB_LOWERINPUT = 0; + parameter [0:0] BOTADDSUB_UPPERINPUT = 0; + parameter [1:0] BOTADDSUB_CARRYSELECT = 0; + parameter [0:0] MODE_8x8 = 0; + parameter [0:0] A_SIGNED = 0; + parameter [0:0] B_SIGNED = 0; + + wire clock = CLK ^ NEG_TRIGGER; + + // internal wires, compare Figure on page 133 of ICE Technology Library 3.0 and Fig 2 on page 2 of Lattice TN1295-DSP + // http://www.latticesemi.com/~/media/LatticeSemi/Documents/TechnicalBriefs/SBTICETechnologyLibrary201608.pdf + // https://www.latticesemi.com/-/media/LatticeSemi/Documents/ApplicationNotes/AD/DSPFunctionUsageGuideforICE40Devices.ashx + wire [15:0] iA, iB, iC, iD; + wire [15:0] iF, iJ, iK, iG; + wire [31:0] iL, iH; + wire [15:0] iW, iX, iP, iQ; + wire [15:0] iY, iZ, iR, iS; + wire HCI, LCI, LCO; + + // Regs C and A + reg [15:0] rC, rA; + always @(posedge clock, posedge IRSTTOP) begin + if (IRSTTOP) begin + rC <= 0; + rA <= 0; + end else if (CE) begin + if (!CHOLD) rC <= C; + if (!AHOLD) rA <= A; + end + end + assign iC = C_REG ? rC : C; + assign iA = A_REG ? rA : A; + + // Regs B and D + reg [15:0] rB, rD; + always @(posedge clock, posedge IRSTTOP) begin + if (IRSTBOT) begin + rB <= 0; + rD <= 0; + end else if (CE) begin + if (!BHOLD) rB <= B; + if (!DHOLD) rD <= D; + end + end + assign iB = B_REG ? rB : B; + assign iD = D_REG ? rD : D; + + // Multiplier Stage + wire [15:0] p_Ah_Bh, p_Al_Bh, p_Ah_Bl, p_Al_Bl; + wire [15:0] Ah, Al, Bh, Bl; + assign Ah = A_SIGNED ? {{8{iA[15]}}, iA[15: 8]} : iA[15: 8]; + assign Al = A_SIGNED ? {{8{iA[ 7]}}, iA[ 7: 0]} : iA[15: 8]; + assign Bh = B_SIGNED ? {{8{iB[15]}}, iB[15: 8]} : iB[15: 8]; + assign Bl = B_SIGNED ? {{8{iB[ 7]}}, iB[ 7: 0]} : iB[15: 8]; + assign p_Ah_Bh = Ah * Bh; + assign p_Al_Bh = Al * Bh; + assign p_Ah_Bl = Ah * Bl; + assign p_Al_Bl = Al * Bl; + + // Regs F and J + reg [15:0] rF, rJ; + always @(posedge clock, posedge IRSTTOP) begin + if (IRSTTOP) begin + rF <= 0; + rJ <= 0; + end else if (CE) begin + rF <= p_Ah_Bh; + if (!MODE_8x8) rJ <= p_Al_Bh; + end + end + assign iF = TOP_8x8_MULT_REG ? rF : p_Ah_Bh; + assign iJ = PIPELINE_16x16_MULT_REG1 ? rJ : p_Al_Bh; + + // Regs K and G + reg [15:0] rK, rG; + always @(posedge clock, posedge IRSTBOT) begin + if (IRSTBOT) begin + rK <= 0; + rG <= 0; + end else if (CE) begin + if (!MODE_8x8) rK <= p_Ah_Bl; + rG <= p_Al_Bl; + end + end + assign iK = PIPELINE_16x16_MULT_REG1 ? rK : p_Ah_Bl; + assign iG = BOT_8x8_MULT_REG ? rG : p_Al_Bl; + + // Adder Stage + reg [31:0] P; + always @* begin + P = iG[7:0]; + P = P + (iG[15:8] + iK[7:0]) << 8; + P = P + (iK[15:8] + iJ[7:0]) << 16; + P = P + (iJ[15:8] + iF[7:0]) << 24; + end + assign iL = P; + + // Reg H + reg [15:0] rH; + always @(posedge clock, posedge IRSTBOT) begin + if (IRSTBOT) begin + rH <= 0; + end else if (CE) begin + if (!MODE_8x8) rH <= iL; + end + end + assign iH = PIPELINE_16x16_MULT_REG2 ? rH : iL; + + // Hi Output Stage + wire [15:0] XW, Oh; + reg [15:0] rQ; + assign iW = TOPADDSUB_UPPERINPUT ? iC : iQ[31:16]; + assign iX = (TOPADDSUB_LOWERINPUT == 0) ? iA : (TOPADDSUB_LOWERINPUT == 1) ? iF : (TOPADDSUB_LOWERINPUT == 2) ? iH[31:16] : {16{iZ[15]}}; + assign {ACCUMCO, XW} = iX + (iW ^ {16{ADDSUBTOP}}) + HCI; + assign CO = ACCUMCO ^ ADDSUBTOP; + assign iP = OLOADTOP ? iC : XW ^ {16{ADDSUBTOP}}; + always @(posedge clock, posedge ORSTTOP) begin + if (ORSTTOP) begin + rQ <= 0; + end else if (CE) begin + if (!OHOLDTOP) rQ <= iP; + end + end + assign iQ = rQ; + assign Oh = (TOPOUTPUT_SELECT == 0) ? iP : (TOPOUTPUT_SELECT == 1) ? iQ : (TOPOUTPUT_SELECT == 2) ? iF : iH[31:16]; + assign HCI = (TOPADDSUB_CARRYSELECT == 0) ? 1'b0 : (TOPADDSUB_CARRYSELECT == 1) ? 1'b1 : (TOPADDSUB_CARRYSELECT == 2) ? LCO : LCO ^ ADDSUBBOT; + assign SIGNEXTOUT = iX[15]; + + // Lo Output Stage + wire [15:0] YZ, Ol; + reg [15:0] rS; + assign iY = BOTADDSUB_UPPERINPUT ? iD : iQ[15:0]; + assign iZ = (BOTADDSUB_LOWERINPUT == 0) ? iB : (BOTADDSUB_LOWERINPUT == 1) ? iG : (BOTADDSUB_LOWERINPUT == 2) ? iH[15:0] : {16{SIGNEXTIN}}; + assign {LCO, YZ} = iZ + (iY ^ {16{ADDSUBBOT}}) + LCI; + assign iR = OLOADBOT ? iD : YZ ^ {16{ADDSUBBOT}}; + always @(posedge clock, posedge ORSTBOT) begin + if (ORSTBOT) begin + rS <= 0; + end else if (CE) begin + if (!OHOLDTOP) rS <= iR; + end + end + assign iS = rS; + assign Ol = (BOTOUTPUT_SELECT == 0) ? iR : (BOTOUTPUT_SELECT == 1) ? iS : (BOTOUTPUT_SELECT == 2) ? iG : iH[15:0]; + assign LCI = (BOTADDSUB_CARRYSELECT == 0) ? 1'b0 : (BOTADDSUB_CARRYSELECT == 1) ? 1'b1 : (BOTADDSUB_CARRYSELECT == 2) ? ACCUMCI : CI; + assign O = {Oh, Ol}; +endmodule diff --git a/techlibs/ice40/tests/test_dsp_model.gtkw b/techlibs/ice40/tests/test_dsp_model.gtkw new file mode 100644 index 000000000..dafe8916f --- /dev/null +++ b/techlibs/ice40/tests/test_dsp_model.gtkw @@ -0,0 +1,87 @@ +[*] +[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI +[*] Tue Feb 19 13:33:31 2019 +[*] +[dumpfile] "/home/clifford/Work/yosys/techlibs/ice40/tests/test_dsp_model.vcd" +[dumpfile_mtime] "Tue Feb 19 13:29:34 2019" +[dumpfile_size] 119605 +[savefile] "/home/clifford/Work/yosys/techlibs/ice40/tests/test_dsp_model.gtkw" +[timestart] 0 +[size] 1850 1362 +[pos] 1816 32 +*-16.399944 42300 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[sst_width] 223 +[signals_width] 142 +[sst_expanded] 1 +[sst_vpaned_height] 420 +@28 +testbench.CLK +testbench.CE +@200 +- +@28 +testbench.REF_ACCUMCO +testbench.UUT_ACCUMCO +@200 +- +@28 +testbench.REF_CO +testbench.UUT_CO +@200 +- +@22 +testbench.REF_O[31:0] +testbench.UUT_O[31:0] +@200 +- +@28 +testbench.REF_SIGNEXTOUT +testbench.UUT_SIGNEXTOUT +@200 +- +@22 +testbench.A[15:0] +testbench.B[15:0] +testbench.C[15:0] +testbench.D[15:0] +@200 +- +@28 +testbench.AHOLD +testbench.BHOLD +testbench.CHOLD +testbench.DHOLD +@200 +- +@28 +testbench.SIGNEXTIN +testbench.ACCUMCI +testbench.CI +@200 +- +@28 +testbench.ADDSUBTOP +testbench.ADDSUBBOT +@200 +- +@28 +testbench.IRSTTOP +testbench.IRSTBOT +@200 +- +@29 +testbench.OHOLDTOP +@28 +testbench.OHOLDBOT +@200 +- +@28 +testbench.OLOADTOP +testbench.OLOADBOT +@200 +- +@28 +testbench.ORSTTOP +testbench.ORSTBOT +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/techlibs/ice40/tests/test_dsp_model.sh b/techlibs/ice40/tests/test_dsp_model.sh new file mode 100644 index 000000000..ad079b2b6 --- /dev/null +++ b/techlibs/ice40/tests/test_dsp_model.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -ex +sed 's/SB_MAC16/SB_MAC16_UUT/; /SB_MAC16_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp_model_uut.v +cat /opt/lscc/iCEcube2.2017.01/verilog/sb_ice_syn.v > test_dsp_model_ref.v +iverilog -s testbench -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v +./test_dsp_model diff --git a/techlibs/ice40/tests/test_dsp_model.v b/techlibs/ice40/tests/test_dsp_model.v new file mode 100644 index 000000000..919bb7917 --- /dev/null +++ b/techlibs/ice40/tests/test_dsp_model.v @@ -0,0 +1,199 @@ +`timescale 1ns / 1ps + +module testbench; + parameter [0:0] NEG_TRIGGER = 0; + parameter [0:0] C_REG = 0; + parameter [0:0] A_REG = 0; + parameter [0:0] B_REG = 0; + parameter [0:0] D_REG = 0; + parameter [0:0] TOP_8x8_MULT_REG = 0; + parameter [0:0] BOT_8x8_MULT_REG = 0; + parameter [0:0] PIPELINE_16x16_MULT_REG1 = 0; + parameter [0:0] PIPELINE_16x16_MULT_REG2 = 0; + parameter [1:0] TOPOUTPUT_SELECT = 0; + parameter [1:0] TOPADDSUB_LOWERINPUT = 2; + parameter [0:0] TOPADDSUB_UPPERINPUT = 1; + parameter [1:0] TOPADDSUB_CARRYSELECT = 2; + parameter [1:0] BOTOUTPUT_SELECT = 0; + parameter [1:0] BOTADDSUB_LOWERINPUT = 2; + parameter [0:0] BOTADDSUB_UPPERINPUT = 1; + parameter [1:0] BOTADDSUB_CARRYSELECT = 2; + parameter [0:0] MODE_8x8 = 0; + parameter [0:0] A_SIGNED = 0; + parameter [0:0] B_SIGNED = 0; + + reg CLK, CE; + reg [15:0] C, A, B, D; + reg AHOLD, BHOLD, CHOLD, DHOLD; + reg IRSTTOP, IRSTBOT; + reg ORSTTOP, ORSTBOT; + reg OLOADTOP, OLOADBOT; + reg ADDSUBTOP, ADDSUBBOT; + reg OHOLDTOP, OHOLDBOT; + reg CI, ACCUMCI, SIGNEXTIN; + + output [31:0] REF_O, UUT_O; + output REF_CO, REF_ACCUMCO, REF_SIGNEXTOUT; + output UUT_CO, UUT_ACCUMCO, UUT_SIGNEXTOUT; + + integer errcount = 0; + + task clkcycle; + begin + #5; + CLK = ~CLK; + #10; + CLK = ~CLK; + #2; + if (REF_O !== UUT_O) begin + $display("ERROR at %1t: REF_O=%b UUT_O=%b", $time, REF_O, UUT_O); + errcount = errcount + 1; + end + if (REF_CO !== UUT_CO) begin + $display("ERROR at %1t: REF_CO=%b UUT_CO=%b", $time, REF_CO, UUT_CO); + errcount = errcount + 1; + end + if (REF_ACCUMCO !== UUT_ACCUMCO) begin + $display("ERROR at %1t: REF_ACCUMCO=%b UUT_ACCUMCO=%b", $time, REF_ACCUMCO, UUT_ACCUMCO); + errcount = errcount + 1; + end + if (REF_SIGNEXTOUT !== UUT_SIGNEXTOUT) begin + $display("ERROR at %1t: REF_SIGNEXTOUT=%b UUT_SIGNEXTOUT=%b", $time, REF_SIGNEXTOUT, UUT_SIGNEXTOUT); + errcount = errcount + 1; + end + #3; + end + endtask + + initial begin + $dumpfile("test_dsp_model.vcd"); + $dumpvars(0, testbench); + + #5; + CLK = NEG_TRIGGER; + CE = 1; + {C, A, B, D} = 0; + {AHOLD, BHOLD, CHOLD, DHOLD} = 0; + {IRSTTOP, IRSTBOT} = 0; + {ORSTTOP, ORSTBOT} = 0; + {OLOADTOP, OLOADBOT} = 0; + {ADDSUBTOP, ADDSUBBOT} = 0; + {OHOLDTOP, OHOLDBOT} = 0; + {CI, ACCUMCI, SIGNEXTIN} = 0; + + // C = 10; + // A = 15; + // B = 22; + // D = 27; + + repeat (10) clkcycle; + + if (errcount == 0) begin + $display("All tests passed."); + end else begin + $display("Caught %1d errors.", errcount); + end + end + + SB_MAC16 #( + .NEG_TRIGGER (NEG_TRIGGER ), + .C_REG (C_REG ), + .A_REG (A_REG ), + .B_REG (B_REG ), + .D_REG (D_REG ), + .TOP_8x8_MULT_REG (TOP_8x8_MULT_REG ), + .BOT_8x8_MULT_REG (BOT_8x8_MULT_REG ), + .PIPELINE_16x16_MULT_REG1 (PIPELINE_16x16_MULT_REG1), + .PIPELINE_16x16_MULT_REG2 (PIPELINE_16x16_MULT_REG2), + .TOPOUTPUT_SELECT (TOPOUTPUT_SELECT ), + .TOPADDSUB_LOWERINPUT (TOPADDSUB_LOWERINPUT ), + .TOPADDSUB_UPPERINPUT (TOPADDSUB_UPPERINPUT ), + .TOPADDSUB_CARRYSELECT (TOPADDSUB_CARRYSELECT ), + .BOTOUTPUT_SELECT (BOTOUTPUT_SELECT ), + .BOTADDSUB_LOWERINPUT (BOTADDSUB_LOWERINPUT ), + .BOTADDSUB_UPPERINPUT (BOTADDSUB_UPPERINPUT ), + .BOTADDSUB_CARRYSELECT (BOTADDSUB_CARRYSELECT ), + .MODE_8x8 (MODE_8x8 ), + .A_SIGNED (A_SIGNED ), + .B_SIGNED (B_SIGNED ) + ) ref ( + .CLK (CLK ), + .CE (CE ), + .C (C ), + .A (A ), + .B (B ), + .D (D ), + .AHOLD (AHOLD ), + .BHOLD (BHOLD ), + .CHOLD (CHOLD ), + .DHOLD (DHOLD ), + .IRSTTOP (IRSTTOP ), + .IRSTBOT (IRSTBOT ), + .ORSTTOP (ORSTTOP ), + .ORSTBOT (ORSTBOT ), + .OLOADTOP (OLOADTOP ), + .OLOADBOT (OLOADBOT ), + .ADDSUBTOP (ADDSUBTOP ), + .ADDSUBBOT (ADDSUBBOT ), + .OHOLDTOP (OHOLDTOP ), + .OHOLDBOT (OHOLDBOT ), + .CI (CI ), + .ACCUMCI (ACCUMCI ), + .SIGNEXTIN (SIGNEXTIN ), + .O (REF_O ), + .CO (REF_CO ), + .ACCUMCO (REF_ACCUMCO ), + .SIGNEXTOUT (REF_SIGNEXTOUT) + ); + + SB_MAC16_UUT #( + .NEG_TRIGGER (NEG_TRIGGER ), + .C_REG (C_REG ), + .A_REG (A_REG ), + .B_REG (B_REG ), + .D_REG (D_REG ), + .TOP_8x8_MULT_REG (TOP_8x8_MULT_REG ), + .BOT_8x8_MULT_REG (BOT_8x8_MULT_REG ), + .PIPELINE_16x16_MULT_REG1 (PIPELINE_16x16_MULT_REG1), + .PIPELINE_16x16_MULT_REG2 (PIPELINE_16x16_MULT_REG2), + .TOPOUTPUT_SELECT (TOPOUTPUT_SELECT ), + .TOPADDSUB_LOWERINPUT (TOPADDSUB_LOWERINPUT ), + .TOPADDSUB_UPPERINPUT (TOPADDSUB_UPPERINPUT ), + .TOPADDSUB_CARRYSELECT (TOPADDSUB_CARRYSELECT ), + .BOTOUTPUT_SELECT (BOTOUTPUT_SELECT ), + .BOTADDSUB_LOWERINPUT (BOTADDSUB_LOWERINPUT ), + .BOTADDSUB_UPPERINPUT (BOTADDSUB_UPPERINPUT ), + .BOTADDSUB_CARRYSELECT (BOTADDSUB_CARRYSELECT ), + .MODE_8x8 (MODE_8x8 ), + .A_SIGNED (A_SIGNED ), + .B_SIGNED (B_SIGNED ) + ) uut ( + .CLK (CLK ), + .CE (CE ), + .C (C ), + .A (A ), + .B (B ), + .D (D ), + .AHOLD (AHOLD ), + .BHOLD (BHOLD ), + .CHOLD (CHOLD ), + .DHOLD (DHOLD ), + .IRSTTOP (IRSTTOP ), + .IRSTBOT (IRSTBOT ), + .ORSTTOP (ORSTTOP ), + .ORSTBOT (ORSTBOT ), + .OLOADTOP (OLOADTOP ), + .OLOADBOT (OLOADBOT ), + .ADDSUBTOP (ADDSUBTOP ), + .ADDSUBBOT (ADDSUBBOT ), + .OHOLDTOP (OHOLDTOP ), + .OHOLDBOT (OHOLDBOT ), + .CI (CI ), + .ACCUMCI (ACCUMCI ), + .SIGNEXTIN (SIGNEXTIN ), + .O (UUT_O ), + .CO (UUT_CO ), + .ACCUMCO (UUT_ACCUMCO ), + .SIGNEXTOUT (UUT_SIGNEXTOUT) + ); +endmodule From 5c4a72c43ef61420b4b099d87949b0fdba0f4b55 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Tue, 19 Feb 2019 14:35:15 -0800 Subject: [PATCH 29/53] Fix normal (non-array) hierarchy -auto-top. Add simple test. --- passes/hierarchy/hierarchy.cc | 18 +++++------ tests/various/hierarchy.sh | 56 +++++++++++++++++++++++++++++++++++ tests/various/run-test.sh | 10 ++++++- 3 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 tests/various/hierarchy.sh diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 332ebdfbb..f112e969e 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -523,15 +523,15 @@ int find_top_mod_score(Design *design, Module *module, dict &db) // Is this an array instance if (celltype.substr(0, 7) == "$array:") { celltype = basic_cell_type(celltype); - // Is this cell is a module instance? - if (celltype[0] != '$') { - auto instModule = design->module(celltype); - // If there is no instance for this, issue a warning. - if (instModule == NULL) { - log_warning("find_top_mod_score: no instance for %s.%s\n", celltype.c_str(), cell->name.c_str()); - } - if (instModule != NULL) - score = max(score, find_top_mod_score(design, instModule, db) + 1); + } + // Is this cell a module instance? + if (celltype[0] != '$') { + auto instModule = design->module(celltype); + // If there is no instance for this, issue a warning. + if (instModule == NULL) { + log_warning("find_top_mod_score: no instance for %s.%s\n", celltype.c_str(), cell->name.c_str()); + } else { + score = max(score, find_top_mod_score(design, instModule, db) + 1); } } } diff --git a/tests/various/hierarchy.sh b/tests/various/hierarchy.sh new file mode 100644 index 000000000..dcb4dc056 --- /dev/null +++ b/tests/various/hierarchy.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# Simple test of hierarchy -auto-top. + +set -e + +../../yosys -q -s - <<- EOY 2>&1 | grep "Automatically selected TOP as design top module" + read_verilog << EOV + module TOP(a, y); + input a; + output [31:0] y; + + aoi12 p [31:0] (a, y); + endmodule + + module aoi12(a, y); + input a; + output y; + assign y = ~a; + endmodule + EOV + hierarchy -auto-top +EOY + +../../yosys -q -s - <<- EOY 2>&1 | grep "Automatically selected TOP as design top module" + read_verilog << EOV + module aoi12(a, y); + input a; + output y; + assign y = ~a; + endmodule + + module TOP(a, y); + input a; + output [31:0] y; + + aoi12 foo (a, y); + endmodule + EOV + hierarchy -auto-top +EOY + +../../yosys -q -s - <<- EOY 2>&1 | grep "Automatically selected noTop as design top module." + read_verilog << EOV + module aoi12(a, y); + input a; + output y; + assign y = ~a; + endmodule + + module noTop(a, y); + input a; + output [31:0] y; + endmodule + EOV + hierarchy -auto-top +EOY diff --git a/tests/various/run-test.sh b/tests/various/run-test.sh index 67e1beb23..7cd1a8650 100755 --- a/tests/various/run-test.sh +++ b/tests/various/run-test.sh @@ -1,6 +1,14 @@ -#!/bin/bash +#!/usr/bin/env bash set -e for x in *.ys; do echo "Running $x.." ../../yosys -ql ${x%.ys}.log $x done +# Run any .sh files in this directory (with the exception of the file - run-test.sh +shell_tests=$(echo *.sh | sed -e 's/run-test.sh//') +if [ "$shell_tests" ]; then + for s in $shell_tests; do + echo "Running $s.." + bash $s >& ${s%.sh}.log + done +fi From dca65d83a0037539464d303ea8751a3e06a92e03 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 20 Feb 2019 11:18:19 +0100 Subject: [PATCH 30/53] Detect and reject cases that do not map well to iCE40 DSPs (yet) Signed-off-by: Clifford Wolf --- passes/pmgen/ice40_dsp.cc | 9 +++++++-- passes/pmgen/ice40_dsp.pmg | 10 ++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 7463d598f..8c50a9393 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -59,10 +59,15 @@ void create_ice40_dsp(ice40_dsp_pm &pm) return; } - log(" replacing $mul with SB_MAC16 cell.\n"); - bool mul_signed = pm.st.mul->getParam("\\A_SIGNED").as_bool(); + if (mul_signed) { + log(" inference of signed iCE40 DSP arithmetic is currently not supported.\n"); + return; + } + + log(" replacing $mul with SB_MAC16 cell.\n"); + Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); pm.module->swap_names(cell, pm.st.mul); diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 58e1ce0e0..96c62e313 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -100,6 +100,16 @@ code addAB sigS addAB = addB; sigS = port(addB, \A); } + if (addAB) { + int natural_mul_width = GetSize(sigA) + GetSize(sigB); + int actual_mul_width = GetSize(sigY); + int actual_acc_width = GetSize(sigS); + + if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) + reject; + if ((actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool())) + reject; + } endcode match muxA From 7bf4e4a1855df442191e3d1cc28eeda7e01d051c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 20 Feb 2019 12:55:20 +0100 Subject: [PATCH 31/53] Improve iCE40 SB_MAC16 model Signed-off-by: Clifford Wolf --- techlibs/ice40/cells_sim.v | 27 ++-- techlibs/ice40/tests/.gitignore | 8 +- techlibs/ice40/tests/test_dsp_model.gtkw | 87 ------------ techlibs/ice40/tests/test_dsp_model.sh | 9 +- techlibs/ice40/tests/test_dsp_model.v | 169 +++++++++++++++++++++-- 5 files changed, 179 insertions(+), 121 deletions(-) delete mode 100644 techlibs/ice40/tests/test_dsp_model.gtkw diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 4a92fccdf..2041693cc 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -1283,7 +1283,7 @@ module SB_MAC16 ( // Regs B and D reg [15:0] rB, rD; - always @(posedge clock, posedge IRSTTOP) begin + always @(posedge clock, posedge IRSTBOT) begin if (IRSTBOT) begin rB <= 0; rD <= 0; @@ -1298,10 +1298,10 @@ module SB_MAC16 ( // Multiplier Stage wire [15:0] p_Ah_Bh, p_Al_Bh, p_Ah_Bl, p_Al_Bl; wire [15:0] Ah, Al, Bh, Bl; - assign Ah = A_SIGNED ? {{8{iA[15]}}, iA[15: 8]} : iA[15: 8]; - assign Al = A_SIGNED ? {{8{iA[ 7]}}, iA[ 7: 0]} : iA[15: 8]; - assign Bh = B_SIGNED ? {{8{iB[15]}}, iB[15: 8]} : iB[15: 8]; - assign Bl = B_SIGNED ? {{8{iB[ 7]}}, iB[ 7: 0]} : iB[15: 8]; + assign Ah = {A_SIGNED ? {8{iA[15]}} : 8'b0, iA[15: 8]}; + assign Al = {A_SIGNED ? {8{iA[ 7]}} : 8'b0, iA[ 7: 0]}; + assign Bh = {B_SIGNED ? {8{iB[15]}} : 8'b0, iB[15: 8]}; + assign Bl = {B_SIGNED ? {8{iB[ 7]}} : 8'b0, iB[ 7: 0]}; assign p_Ah_Bh = Ah * Bh; assign p_Al_Bh = Al * Bh; assign p_Ah_Bl = Ah * Bl; @@ -1336,17 +1336,10 @@ module SB_MAC16 ( assign iG = BOT_8x8_MULT_REG ? rG : p_Al_Bl; // Adder Stage - reg [31:0] P; - always @* begin - P = iG[7:0]; - P = P + (iG[15:8] + iK[7:0]) << 8; - P = P + (iK[15:8] + iJ[7:0]) << 16; - P = P + (iJ[15:8] + iF[7:0]) << 24; - end - assign iL = P; + assign iL = iG + (iK << 8) + (iJ << 8) + (iF << 16); // Reg H - reg [15:0] rH; + reg [31:0] rH; always @(posedge clock, posedge IRSTBOT) begin if (IRSTBOT) begin rH <= 0; @@ -1359,7 +1352,7 @@ module SB_MAC16 ( // Hi Output Stage wire [15:0] XW, Oh; reg [15:0] rQ; - assign iW = TOPADDSUB_UPPERINPUT ? iC : iQ[31:16]; + assign iW = TOPADDSUB_UPPERINPUT ? iC : iQ; assign iX = (TOPADDSUB_LOWERINPUT == 0) ? iA : (TOPADDSUB_LOWERINPUT == 1) ? iF : (TOPADDSUB_LOWERINPUT == 2) ? iH[31:16] : {16{iZ[15]}}; assign {ACCUMCO, XW} = iX + (iW ^ {16{ADDSUBTOP}}) + HCI; assign CO = ACCUMCO ^ ADDSUBTOP; @@ -1379,7 +1372,7 @@ module SB_MAC16 ( // Lo Output Stage wire [15:0] YZ, Ol; reg [15:0] rS; - assign iY = BOTADDSUB_UPPERINPUT ? iD : iQ[15:0]; + assign iY = BOTADDSUB_UPPERINPUT ? iD : iS; assign iZ = (BOTADDSUB_LOWERINPUT == 0) ? iB : (BOTADDSUB_LOWERINPUT == 1) ? iG : (BOTADDSUB_LOWERINPUT == 2) ? iH[15:0] : {16{SIGNEXTIN}}; assign {LCO, YZ} = iZ + (iY ^ {16{ADDSUBBOT}}) + LCI; assign iR = OLOADBOT ? iD : YZ ^ {16{ADDSUBBOT}}; @@ -1387,7 +1380,7 @@ module SB_MAC16 ( if (ORSTBOT) begin rS <= 0; end else if (CE) begin - if (!OHOLDTOP) rS <= iR; + if (!OHOLDBOT) rS <= iR; end end assign iS = rS; diff --git a/techlibs/ice40/tests/.gitignore b/techlibs/ice40/tests/.gitignore index b58f9ad4a..9795152c2 100644 --- a/techlibs/ice40/tests/.gitignore +++ b/techlibs/ice40/tests/.gitignore @@ -1,2 +1,6 @@ -test_ffs_[01][01][01][01][01]_* -test_bram_[0-9]* +/test_ffs_[01][01][01][01][01]_* +/test_bram_[0-9]* +/test_dsp_model +/test_dsp_model.vcd +/test_dsp_model_ref.v +/test_dsp_model_uut.v diff --git a/techlibs/ice40/tests/test_dsp_model.gtkw b/techlibs/ice40/tests/test_dsp_model.gtkw deleted file mode 100644 index dafe8916f..000000000 --- a/techlibs/ice40/tests/test_dsp_model.gtkw +++ /dev/null @@ -1,87 +0,0 @@ -[*] -[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI -[*] Tue Feb 19 13:33:31 2019 -[*] -[dumpfile] "/home/clifford/Work/yosys/techlibs/ice40/tests/test_dsp_model.vcd" -[dumpfile_mtime] "Tue Feb 19 13:29:34 2019" -[dumpfile_size] 119605 -[savefile] "/home/clifford/Work/yosys/techlibs/ice40/tests/test_dsp_model.gtkw" -[timestart] 0 -[size] 1850 1362 -[pos] 1816 32 -*-16.399944 42300 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -[sst_width] 223 -[signals_width] 142 -[sst_expanded] 1 -[sst_vpaned_height] 420 -@28 -testbench.CLK -testbench.CE -@200 -- -@28 -testbench.REF_ACCUMCO -testbench.UUT_ACCUMCO -@200 -- -@28 -testbench.REF_CO -testbench.UUT_CO -@200 -- -@22 -testbench.REF_O[31:0] -testbench.UUT_O[31:0] -@200 -- -@28 -testbench.REF_SIGNEXTOUT -testbench.UUT_SIGNEXTOUT -@200 -- -@22 -testbench.A[15:0] -testbench.B[15:0] -testbench.C[15:0] -testbench.D[15:0] -@200 -- -@28 -testbench.AHOLD -testbench.BHOLD -testbench.CHOLD -testbench.DHOLD -@200 -- -@28 -testbench.SIGNEXTIN -testbench.ACCUMCI -testbench.CI -@200 -- -@28 -testbench.ADDSUBTOP -testbench.ADDSUBBOT -@200 -- -@28 -testbench.IRSTTOP -testbench.IRSTBOT -@200 -- -@29 -testbench.OHOLDTOP -@28 -testbench.OHOLDBOT -@200 -- -@28 -testbench.OLOADTOP -testbench.OLOADBOT -@200 -- -@28 -testbench.ORSTTOP -testbench.ORSTBOT -[pattern_trace] 1 -[pattern_trace] 0 diff --git a/techlibs/ice40/tests/test_dsp_model.sh b/techlibs/ice40/tests/test_dsp_model.sh index ad079b2b6..1bc0cc688 100644 --- a/techlibs/ice40/tests/test_dsp_model.sh +++ b/techlibs/ice40/tests/test_dsp_model.sh @@ -2,5 +2,10 @@ set -ex sed 's/SB_MAC16/SB_MAC16_UUT/; /SB_MAC16_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp_model_uut.v cat /opt/lscc/iCEcube2.2017.01/verilog/sb_ice_syn.v > test_dsp_model_ref.v -iverilog -s testbench -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v -./test_dsp_model +for tb in testbench \ + testbench_comb_8x8_A testbench_comb_8x8_B testbench_comb_16x16 \ + testbench_seq_16x16_A testbench_seq_16x16_B +do + iverilog -s $tb -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v + vvp -N ./test_dsp_model +done diff --git a/techlibs/ice40/tests/test_dsp_model.v b/techlibs/ice40/tests/test_dsp_model.v index 919bb7917..594bd4ad3 100644 --- a/techlibs/ice40/tests/test_dsp_model.v +++ b/techlibs/ice40/tests/test_dsp_model.v @@ -11,13 +11,13 @@ module testbench; parameter [0:0] PIPELINE_16x16_MULT_REG1 = 0; parameter [0:0] PIPELINE_16x16_MULT_REG2 = 0; parameter [1:0] TOPOUTPUT_SELECT = 0; - parameter [1:0] TOPADDSUB_LOWERINPUT = 2; + parameter [1:0] TOPADDSUB_LOWERINPUT = 0; parameter [0:0] TOPADDSUB_UPPERINPUT = 1; - parameter [1:0] TOPADDSUB_CARRYSELECT = 2; + parameter [1:0] TOPADDSUB_CARRYSELECT = 0; parameter [1:0] BOTOUTPUT_SELECT = 0; - parameter [1:0] BOTADDSUB_LOWERINPUT = 2; + parameter [1:0] BOTADDSUB_LOWERINPUT = 0; parameter [0:0] BOTADDSUB_UPPERINPUT = 1; - parameter [1:0] BOTADDSUB_CARRYSELECT = 2; + parameter [1:0] BOTADDSUB_CARRYSELECT = 0; parameter [0:0] MODE_8x8 = 0; parameter [0:0] A_SIGNED = 0; parameter [0:0] B_SIGNED = 0; @@ -46,7 +46,7 @@ module testbench; CLK = ~CLK; #2; if (REF_O !== UUT_O) begin - $display("ERROR at %1t: REF_O=%b UUT_O=%b", $time, REF_O, UUT_O); + $display("ERROR at %1t: REF_O=%b UUT_O=%b DIFF=%b", $time, REF_O, UUT_O, REF_O ^ UUT_O); errcount = errcount + 1; end if (REF_CO !== UUT_CO) begin @@ -69,29 +69,47 @@ module testbench; $dumpfile("test_dsp_model.vcd"); $dumpvars(0, testbench); - #5; + #2; CLK = NEG_TRIGGER; CE = 1; {C, A, B, D} = 0; {AHOLD, BHOLD, CHOLD, DHOLD} = 0; - {IRSTTOP, IRSTBOT} = 0; - {ORSTTOP, ORSTBOT} = 0; {OLOADTOP, OLOADBOT} = 0; {ADDSUBTOP, ADDSUBBOT} = 0; {OHOLDTOP, OHOLDBOT} = 0; {CI, ACCUMCI, SIGNEXTIN} = 0; - // C = 10; - // A = 15; - // B = 22; - // D = 27; + {IRSTTOP, IRSTBOT} = ~0; + {ORSTTOP, ORSTBOT} = ~0; - repeat (10) clkcycle; + #3; + {IRSTTOP, IRSTBOT} = 0; + {ORSTTOP, ORSTBOT} = 0; + + repeat (300) begin + clkcycle; + + A = $urandom; + B = $urandom; + C = $urandom; + D = $urandom; + + {AHOLD, BHOLD, CHOLD, DHOLD} = $urandom & $urandom & $urandom; + {OLOADTOP, OLOADBOT} = $urandom & $urandom & $urandom; + {ADDSUBTOP, ADDSUBBOT} = $urandom & $urandom & $urandom; + {OHOLDTOP, OHOLDBOT} = $urandom & $urandom & $urandom; + {CI, ACCUMCI, SIGNEXTIN} = $urandom & $urandom & $urandom; + + {IRSTTOP, IRSTBOT} = $urandom & $urandom & $urandom; + {ORSTTOP, ORSTBOT} = $urandom & $urandom & $urandom; + end if (errcount == 0) begin $display("All tests passed."); + $finish; end else begin $display("Caught %1d errors.", errcount); + $stop; end end @@ -197,3 +215,128 @@ module testbench; .SIGNEXTOUT (UUT_SIGNEXTOUT) ); endmodule + +module testbench_comb_8x8_A; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (2), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (0), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (0), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (2), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (0), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (0), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (0), + .B_SIGNED (0) + ) testbench (); +endmodule + +module testbench_comb_8x8_B; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (1), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (1), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (0), + .B_SIGNED (0) + ) testbench (); +endmodule + +module testbench_comb_16x16; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (0), + .B_SIGNED (0) + ) testbench (); +endmodule + +module testbench_seq_16x16_A; + testbench #( + .NEG_TRIGGER (0), + .C_REG (1), + .A_REG (1), + .B_REG (1), + .D_REG (1), + .TOP_8x8_MULT_REG (1), + .BOT_8x8_MULT_REG (1), + .PIPELINE_16x16_MULT_REG1 (1), + .PIPELINE_16x16_MULT_REG2 (1), + .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (0), + .B_SIGNED (0) + ) testbench (); +endmodule + +module testbench_seq_16x16_B; + testbench #( + .NEG_TRIGGER (0), + .C_REG (1), + .A_REG (1), + .B_REG (1), + .D_REG (1), + .TOP_8x8_MULT_REG (1), + .BOT_8x8_MULT_REG (1), + .PIPELINE_16x16_MULT_REG1 (1), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (1), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (0), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (1), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (0), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (0), + .B_SIGNED (0) + ) testbench (); +endmodule From 246391200e3e0d47ee571d4d77dd0744dba0e164 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 20 Feb 2019 16:36:42 +0100 Subject: [PATCH 32/53] Add FF support to wreduce Signed-off-by: Clifford Wolf --- kernel/rtlil.cc | 3 ++ passes/opt/wreduce.cc | 71 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 8404db5e9..d4aebcda9 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -2410,6 +2410,9 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) if (connections_.count("\\Y")) parameters["\\Y_WIDTH"] = GetSize(connections_["\\Y"]); + if (connections_.count("\\Q")) + parameters["\\WIDTH"] = GetSize(connections_["\\Q"]); + check(); } diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 8063b86a6..3aa916ec2 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -38,7 +38,8 @@ struct WreduceConfig "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt", "$add", "$sub", "$mul", // "$div", "$mod", "$pow", - "$mux", "$pmux" + "$mux", "$pmux", + "$dff", "$adff" }); } }; @@ -134,6 +135,71 @@ struct WreduceWorker module->connect(sig_y.extract(n_kept, n_removed), sig_removed); } + void run_cell_dff(Cell *cell) + { + // Reduce size of FF if inputs are just sign/zero extended or output bit is not used + + SigSpec sig_d = mi.sigmap(cell->getPort("\\D")); + SigSpec sig_q = mi.sigmap(cell->getPort("\\Q")); + + int width_before = GetSize(sig_q); + + if (width_before == 0) + return; + + bool zero_ext = sig_d[GetSize(sig_d)-1] == State::S0; + bool sign_ext = !zero_ext; + + for (int i = GetSize(sig_q)-1; i >= 0; i--) + { + if (zero_ext && sig_d[i] == State::S0) { + module->connect(sig_q[i], State::S0); + sig_d.remove(i); + sig_q.remove(i); + continue; + } + + if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1]) { + module->connect(sig_q[i], sig_q[i-1]); + sig_d.remove(i); + sig_q.remove(i); + continue; + } + + auto info = mi.query(sig_q[i]); + if (!info->is_output && GetSize(info->ports) <= 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) { + sig_d.remove(i); + sig_q.remove(i); + zero_ext = false; + sign_ext = false; + continue; + } + + break; + } + + if (width_before == GetSize(sig_q)) + return; + + if (GetSize(sig_q) == 0) { + log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type)); + return; + } + + log("Removed top %d bits (of %d) from mux cell %s.%s (%s).\n", width_before - GetSize(sig_q), width_before, + log_id(module), log_id(cell), log_id(cell->type)); + + for (auto bit : sig_d) + work_queue_bits.insert(bit); + + for (auto bit : sig_q) + work_queue_bits.insert(bit); + + cell->setPort("\\D", sig_d); + cell->setPort("\\Q", sig_q); + cell->fixup_parameters(); + } + void run_reduce_inport(Cell *cell, char port, int max_port_size, bool &port_signed, bool &did_something) { port_signed = cell->getParam(stringf("\\%c_SIGNED", port)).as_bool(); @@ -176,6 +242,9 @@ struct WreduceWorker if (cell->type.in("$mux", "$pmux")) return run_cell_mux(cell); + if (cell->type.in("$dff", "$adff")) + return run_cell_dff(cell); + SigSpec sig = mi.sigmap(cell->getPort("\\Y")); if (sig.has_const()) From 218e9051bbdbbd00620a21e6918e6a4b9bc07867 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 20 Feb 2019 16:42:27 +0100 Subject: [PATCH 33/53] Add "synth_ice40 -dsp" Signed-off-by: Clifford Wolf --- passes/pmgen/ice40_dsp.cc | 8 ++++---- techlibs/ice40/synth_ice40.cc | 30 +++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 8c50a9393..3e342453d 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -159,8 +159,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setPort("\\ADDSUBBOT", State::S0); } - cell->setPort("\\ORTSTOP", State::S0); - cell->setPort("\\ORTSBOT", State::S0); + cell->setPort("\\ORSTTOP", State::S0); + cell->setPort("\\ORSTBOT", State::S0); cell->setPort("\\OHOLDTOP", State::S0); cell->setPort("\\OHOLDBOT", State::S0); @@ -181,8 +181,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam("\\TOP_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0); cell->setParam("\\BOT_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0); - cell->setParam("\\PIPELINE_16X16_MULT_REG1", pm.st.ffY ? State::S1 : State::S0); - cell->setParam("\\PIPELINE_16X16_MULT_REG2", State::S0); + cell->setParam("\\PIPELINE_16x16_MULT_REG1", pm.st.ffY ? State::S1 : State::S0); + cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0); cell->setParam("\\TOPOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2)); cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index f900453e8..d6d047fe7 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -79,6 +79,9 @@ struct SynthIce40Pass : public ScriptPass log(" -nobram\n"); log(" do not use SB_RAM40_4K* cells in output netlist\n"); log("\n"); + log(" -dsp\n"); + log(" use iCE40 UltraPlus DSP cells for large arithmetic\n"); + log("\n"); log(" -noabc\n"); log(" use built-in Yosys LUT techmapping instead of abc\n"); log("\n"); @@ -96,7 +99,7 @@ struct SynthIce40Pass : public ScriptPass } string top_opt, blif_file, edif_file, json_file; - bool nocarry, nodffe, nobram, flatten, retime, relut, noabc, abc2, vpr; + bool nocarry, nodffe, nobram, dsp, flatten, retime, relut, noabc, abc2, vpr; int min_ce_use; void clear_flags() YS_OVERRIDE @@ -109,6 +112,7 @@ struct SynthIce40Pass : public ScriptPass nodffe = false; min_ce_use = -1; nobram = false; + dsp = false; flatten = true; retime = false; relut = false; @@ -181,6 +185,10 @@ struct SynthIce40Pass : public ScriptPass nobram = true; continue; } + if (args[argidx] == "-dsp") { + dsp = true; + continue; + } if (args[argidx] == "-noabc") { noabc = true; continue; @@ -214,11 +222,11 @@ struct SynthIce40Pass : public ScriptPass { run("read_verilog -lib +/ice40/cells_sim.v"); run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt.c_str())); + run("proc"); } if (flatten && check_label("flatten", "(unless -noflatten)")) { - run("proc"); run("flatten"); run("tribuf -logic"); run("deminout"); @@ -226,7 +234,23 @@ struct SynthIce40Pass : public ScriptPass if (check_label("coarse")) { - run("synth -lut 4 -run coarse"); + run("opt_expr"); + run("opt_clean"); + run("check"); + run("opt"); + run("wreduce"); + run("share"); + run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); + run("opt_expr"); + run("opt_clean"); + if (help_mode || dsp) + run("ice40_dsp", "(if -dsp)"); + run("alumacc"); + run("opt"); + run("fsm"); + run("opt -fast"); + run("memory -nomap"); + run("opt_clean"); } if (!nobram && check_label("bram", "(skip if -nobram)")) From 84999a7e680648dff674ce55f634a675852b7dc3 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 20 Feb 2019 17:18:59 +0100 Subject: [PATCH 34/53] Add ice40 test_dsp_map test case generator Signed-off-by: Clifford Wolf --- techlibs/ice40/tests/.gitignore | 4 ++ techlibs/ice40/tests/test_dsp_map.sh | 95 ++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 techlibs/ice40/tests/test_dsp_map.sh diff --git a/techlibs/ice40/tests/.gitignore b/techlibs/ice40/tests/.gitignore index 9795152c2..300ce9aa6 100644 --- a/techlibs/ice40/tests/.gitignore +++ b/techlibs/ice40/tests/.gitignore @@ -4,3 +4,7 @@ /test_dsp_model.vcd /test_dsp_model_ref.v /test_dsp_model_uut.v +/test_dsp_map +/test_dsp_map_tb.v +/test_dsp_map_top.v +/test_dsp_map_syn.v diff --git a/techlibs/ice40/tests/test_dsp_map.sh b/techlibs/ice40/tests/test_dsp_map.sh new file mode 100644 index 000000000..5982e5b34 --- /dev/null +++ b/techlibs/ice40/tests/test_dsp_map.sh @@ -0,0 +1,95 @@ +#!/bin/bash +set -ex + +SZA=$(( 3 + $RANDOM % 13 )) +SZB=$(( 3 + $RANDOM % 13 )) +SZO=$(( 3 + $RANDOM % 29 )) + +C0=clk$(( $RANDOM & 1)) +C1=clk$(( $RANDOM & 1)) +C2=clk$(( $RANDOM & 1)) +C3=clk$(( $RANDOM & 1)) + +E0=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) +E1=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) +E2=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) +E3=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) + +SP=$( test $(( $RANDOM & 1 )) -eq 0 && echo S || echo P ) + +RC=$( test $(( $RANDOM & 1 )) -eq 0 && echo "reset" || echo "!reset" ) +RV="32'h$( echo $RANDOM | md5sum | cut -c1-8 )" + +cat > test_dsp_map_top.v << EOT +module top ( + input clk0, clk1, reset, + input [$SZA:0] A, + input [$SZB:0] B, + output [$SZO:0] O +); + reg [15:0] AA, BB; + reg [31:0] P, S; + + always @($E0 $C0) AA <= A; + always @($E1 $C1) BB <= B; + always @($E2 $C2) P <= AA * BB; + always @($E3 $C3) S <= $RC ? $RV : S + P; + assign O = $SP; +endmodule +EOT + +cat > test_dsp_map_tb.v << EOT +\`timescale 1ns / 1ps +module testbench; + reg clk1, clk0, reset; + reg [$SZA:0] A; + reg [$SZB:0] B; + + wire [$SZO:0] O_top, O_syn; + + top top_inst (.clk0(clk0), .clk1(clk1), .reset(reset), .A(A), .B(B), .O(O_top)); + syn syn_inst (.clk0(clk0), .clk1(clk1), .reset(reset), .A(A), .B(B), .O(O_syn)); + + initial begin + #2; + clk0 = 0; + clk1 = 0; + reset = 1; + A = 0; + B = 0; + + repeat (3) begin + #2; clk0 = ~clk0; + #2; clk0 = ~clk0; + #2; clk1 = ~clk1; + #2; clk1 = ~clk1; + end + + repeat (100) begin + #2; + A = \$urandom; + B = \$urandom; + reset = \$urandom & \$urandom & \$urandom & \$urandom; + if (\$urandom & 1) begin + #2; clk0 = ~clk0; + #2; clk0 = ~clk0; + end else begin + #2; clk1 = ~clk1; + #2; clk1 = ~clk1; + end + #2; + if (O_top !== O_syn) begin + \$display("ERROR: O_top=%b O_syn=%b", O_top, O_syn); + \$stop; + end + \$display("OK O_top=O_syn=%b", O_top); + end + + \$finish; + end +endmodule +EOT + +../../../yosys -p 'read_verilog test_dsp_map_top.v; synth_ice40 -dsp; rename top syn; write_verilog test_dsp_map_syn.v' +iverilog -o test_dsp_map -s testbench test_dsp_map_tb.v test_dsp_map_top.v test_dsp_map_syn.v ../cells_sim.v +vvp -N test_dsp_map From 4035ec8933cd187670788fb6eca5cefa80fe7170 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 20 Feb 2019 15:45:45 -0800 Subject: [PATCH 35/53] Remove simple_defparam tests --- tests/simple_defparam/run-test.sh | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100755 tests/simple_defparam/run-test.sh diff --git a/tests/simple_defparam/run-test.sh b/tests/simple_defparam/run-test.sh deleted file mode 100755 index 137e15076..000000000 --- a/tests/simple_defparam/run-test.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -OPTIND=1 -seed="" # default to no seed specified -while getopts "S:" opt -do - case "$opt" in - S) arg="${OPTARG#"${OPTARG%%[![:space:]]*}"}" # remove leading space - seed="SEED=$arg" ;; - esac -done -shift "$((OPTIND-1))" - -# check for Icarus Verilog -if ! which iverilog > /dev/null ; then - echo "$0: Error: Icarus Verilog 'iverilog' not found." - exit 1 -fi - -cp ../simple/*.v . -exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-B \"-defparam\"" From 2fe1c830eb8aea783c75529b42cab04208cea690 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Feb 2019 13:28:46 +0100 Subject: [PATCH 36/53] Bugfix in ice40_dsp Signed-off-by: Clifford Wolf --- passes/pmgen/ice40_dsp.cc | 4 +-- techlibs/ice40/tests/.gitignore | 1 + techlibs/ice40/tests/test_dsp_map.sh | 52 +++++++++++++++++----------- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index 3e342453d..3a054a463 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -91,8 +91,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setPort("\\C", CD.extract(0, 16)); cell->setPort("\\D", CD.extract(16, 16)); - cell->setParam("\\A_REG", pm.st.ffA ? State::S0 : State::S1); - cell->setParam("\\B_REG", pm.st.ffB ? State::S0 : State::S1); + cell->setParam("\\A_REG", pm.st.ffA ? State::S1 : State::S0); + cell->setParam("\\B_REG", pm.st.ffB ? State::S1 : State::S0); cell->setPort("\\AHOLD", State::S0); cell->setPort("\\BHOLD", State::S0); diff --git a/techlibs/ice40/tests/.gitignore b/techlibs/ice40/tests/.gitignore index 300ce9aa6..120286550 100644 --- a/techlibs/ice40/tests/.gitignore +++ b/techlibs/ice40/tests/.gitignore @@ -5,6 +5,7 @@ /test_dsp_model_ref.v /test_dsp_model_uut.v /test_dsp_map +/test_dsp_map.vcd /test_dsp_map_tb.v /test_dsp_map_top.v /test_dsp_map_syn.v diff --git a/techlibs/ice40/tests/test_dsp_map.sh b/techlibs/ice40/tests/test_dsp_map.sh index 5982e5b34..3f7f134e4 100644 --- a/techlibs/ice40/tests/test_dsp_map.sh +++ b/techlibs/ice40/tests/test_dsp_map.sh @@ -1,26 +1,28 @@ #!/bin/bash set -ex -SZA=$(( 3 + $RANDOM % 13 )) -SZB=$(( 3 + $RANDOM % 13 )) -SZO=$(( 3 + $RANDOM % 29 )) +for iter in {1..100} +do + SZA=$(( 3 + $RANDOM % 13 )) + SZB=$(( 3 + $RANDOM % 13 )) + SZO=$(( 3 + $RANDOM % 29 )) -C0=clk$(( $RANDOM & 1)) -C1=clk$(( $RANDOM & 1)) -C2=clk$(( $RANDOM & 1)) -C3=clk$(( $RANDOM & 1)) + C0=clk$(( $RANDOM & 1)) + C1=clk$(( $RANDOM & 1)) + C2=clk$(( $RANDOM & 1)) + C3=clk$(( $RANDOM & 1)) -E0=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) -E1=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) -E2=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) -E3=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) + E0=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) + E1=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) + E2=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) + E3=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) -SP=$( test $(( $RANDOM & 1 )) -eq 0 && echo S || echo P ) + SP=$( test $(( $RANDOM & 1 )) -eq 0 && echo S || echo P ) -RC=$( test $(( $RANDOM & 1 )) -eq 0 && echo "reset" || echo "!reset" ) -RV="32'h$( echo $RANDOM | md5sum | cut -c1-8 )" + RC=$( test $(( $RANDOM & 1 )) -eq 0 && echo "reset" || echo "!reset" ) + RV="32'h$( echo $RANDOM | md5sum | cut -c1-8 )" -cat > test_dsp_map_top.v << EOT + cat > test_dsp_map_top.v << EOT module top ( input clk0, clk1, reset, input [$SZA:0] A, @@ -38,7 +40,7 @@ module top ( endmodule EOT -cat > test_dsp_map_tb.v << EOT + cat > test_dsp_map_tb.v << EOT \`timescale 1ns / 1ps module testbench; reg clk1, clk0, reset; @@ -51,10 +53,14 @@ module testbench; syn syn_inst (.clk0(clk0), .clk1(clk1), .reset(reset), .A(A), .B(B), .O(O_syn)); initial begin + // \$dumpfile("test_dsp_map.vcd"); + // \$dumpvars(0, testbench); + #2; clk0 = 0; clk1 = 0; reset = 1; + reset = $RC; A = 0; B = 0; @@ -82,14 +88,20 @@ module testbench; \$display("ERROR: O_top=%b O_syn=%b", O_top, O_syn); \$stop; end - \$display("OK O_top=O_syn=%b", O_top); + // \$display("OK O_top=O_syn=%b", O_top); end + \$display("Test passed."); \$finish; end endmodule EOT -../../../yosys -p 'read_verilog test_dsp_map_top.v; synth_ice40 -dsp; rename top syn; write_verilog test_dsp_map_syn.v' -iverilog -o test_dsp_map -s testbench test_dsp_map_tb.v test_dsp_map_top.v test_dsp_map_syn.v ../cells_sim.v -vvp -N test_dsp_map + ../../../yosys -p 'read_verilog test_dsp_map_top.v; synth_ice40 -dsp; rename top syn; write_verilog test_dsp_map_syn.v' + iverilog -o test_dsp_map -s testbench test_dsp_map_tb.v test_dsp_map_top.v test_dsp_map_syn.v ../cells_sim.v + vvp -N test_dsp_map +done + +: "" +: "#### All tests passed. ####" +: "" From 2da4c9c8f0a849434f657ac4a56de11d35e1c41e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Feb 2019 13:48:23 +0100 Subject: [PATCH 37/53] Fix opt_rmdff handling of $_DFFSR_???_ and $_DLATCHSR_???_, fixes #816 Signed-off-by: Clifford Wolf --- passes/opt/opt_rmdff.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc index 5880254c1..e8570f0eb 100644 --- a/passes/opt/opt_rmdff.cc +++ b/passes/opt/opt_rmdff.cc @@ -174,8 +174,6 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell) cell->unsetParam("\\CLR_POLARITY"); cell->unsetPort("\\SET"); cell->unsetPort("\\CLR"); - - return true; } else { @@ -186,11 +184,12 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell) cell->unsetParam("\\CLR_POLARITY"); cell->unsetPort("\\SET"); cell->unsetPort("\\CLR"); - - return true; } + + return true; } - else + + if (!hasreset) { IdString new_type; @@ -207,8 +206,10 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell) cell->unsetPort("\\S"); cell->unsetPort("\\R"); - return did_something; + return true; } + + return did_something; } bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch) From 953e0bf88d363180619452dd0049268ee9cfbb67 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Feb 2019 14:27:46 +0100 Subject: [PATCH 38/53] Rename "yosys -D" to "yosys -U", add "yosys -D" with expected behavior Signed-off-by: Clifford Wolf --- kernel/driver.cc | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/kernel/driver.cc b/kernel/driver.cc index 178641101..ca8f6a7b5 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -179,6 +179,7 @@ int main(int argc, char **argv) { std::string frontend_command = "auto"; std::string backend_command = "auto"; + std::vector vlog_defines; std::vector passes_commands; std::vector plugin_filenames; std::string output_filename = ""; @@ -268,7 +269,10 @@ int main(int argc, char **argv) printf(" -A\n"); printf(" will call abort() at the end of the script. for debugging\n"); printf("\n"); - printf(" -D [:]\n"); + printf(" -D [=]\n"); + printf(" set the specified Verilog define (via \"read -define\")\n"); + printf("\n"); + printf(" -U [:]\n"); printf(" dump the design when printing the specified log header to a file.\n"); printf(" yosys_dump_.il is used as filename if none is specified.\n"); printf(" Use 'ALL' as to dump at every header.\n"); @@ -307,7 +311,7 @@ int main(int argc, char **argv) } int opt; - while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:E:")) != -1) + while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:U:E:")) != -1) { switch (opt) { @@ -408,6 +412,9 @@ int main(int argc, char **argv) std::regex_constants::egrep)); break; case 'D': + vlog_defines.push_back(optarg); + break; + case 'U': { auto args = split_tokens(optarg, ":"); if (!args.empty() && args[0] == "ALL") { @@ -473,6 +480,13 @@ int main(int argc, char **argv) shell(yosys_design); } + if (!vlog_defines.empty()) { + std::string vdef_cmd = "read -define"; + for (auto vdef : vlog_defines) + vdef_cmd += " " + vdef; + run_pass(vdef_cmd); + } + while (optind < argc) run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL); From 0a6588569bb859d74876bf50956cb5f02cf3a31d Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Feb 2019 15:51:59 +0100 Subject: [PATCH 39/53] Rename "yosys -U" to "yosys -P" to avoid confusion about "undefine" Signed-off-by: Clifford Wolf --- kernel/driver.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/driver.cc b/kernel/driver.cc index ca8f6a7b5..a0bb7e60a 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -272,7 +272,7 @@ int main(int argc, char **argv) printf(" -D [=]\n"); printf(" set the specified Verilog define (via \"read -define\")\n"); printf("\n"); - printf(" -U [:]\n"); + printf(" -P [:]\n"); printf(" dump the design when printing the specified log header to a file.\n"); printf(" yosys_dump_.il is used as filename if none is specified.\n"); printf(" Use 'ALL' as to dump at every header.\n"); @@ -311,7 +311,7 @@ int main(int argc, char **argv) } int opt; - while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:U:E:")) != -1) + while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1) { switch (opt) { @@ -414,7 +414,7 @@ int main(int argc, char **argv) case 'D': vlog_defines.push_back(optarg); break; - case 'U': + case 'P': { auto args = split_tokens(optarg, ":"); if (!args.empty() && args[0] == "ALL") { From 28fba903c595710c401a6c7d49e7bfd3f8c64efc Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Feb 2019 17:36:51 +0100 Subject: [PATCH 40/53] Fix segfault in printing of some internal error messages Signed-off-by: Clifford Wolf --- frontends/ast/genrtlil.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index e66625228..bdc34d490 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -792,7 +792,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun // everything should have been handled above -> print error if not. default: for (auto f : log_files) - current_ast->dumpAst(f, "verilog-ast> "); + current_ast_mod->dumpAst(f, "verilog-ast> "); log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n", type2str(type).c_str()); } @@ -1565,7 +1565,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // everything should have been handled above -> print error if not. default: for (auto f : log_files) - current_ast->dumpAst(f, "verilog-ast> "); + current_ast_mod->dumpAst(f, "verilog-ast> "); type_name = type2str(type); log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n", type_name.c_str()); } From 974927adcf916fc953ae4b756fd1806cfa423655 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Feb 2019 17:55:33 +0100 Subject: [PATCH 41/53] Fix handling of expression width in $past, fixes #810 Signed-off-by: Clifford Wolf --- frontends/ast/simplify.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 83714f897..6ae62ead8 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1778,7 +1778,7 @@ skip_dynamic_range_lvalue_expansion:; if (str == "\\$past") { - if (width_hint <= 0) + if (width_hint < 0) goto replace_fcall_later; int num_steps = 1; From 8e789da74c6702ededc668e3dbd899de8d0c2821 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 21 Feb 2019 09:22:29 -0800 Subject: [PATCH 42/53] Revert "Add -B option to autotest.sh to append to backend_opts" This reverts commit 281f2aadcab01465f83a3f3a697eec42503e9f8b. --- tests/tools/autotest.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index 6fdd1e80a..218edf931 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -28,7 +28,7 @@ if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdat ( set -ex; ${CC:-gcc} -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1 fi -while getopts xmGl:wkjvref:s:p:n:S:I:B:-: opt; do +while getopts xmGl:wkjvref:s:p:n:S:I:-: opt; do case "$opt" in x) use_xsim=true ;; @@ -65,8 +65,6 @@ while getopts xmGl:wkjvref:s:p:n:S:I:B:-: opt; do include_opts="$include_opts -I $OPTARG" xinclude_opts="$xinclude_opts -i $OPTARG" minclude_opts="$minclude_opts +incdir+$OPTARG" ;; - B) - backend_opts="$backend_opts $OPTARG" ;; -) case "${OPTARG}" in xfirrtl) @@ -84,7 +82,7 @@ while getopts xmGl:wkjvref:s:p:n:S:I:B:-: opt; do ;; esac;; *) - echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] [-B backend_opt] [--xfirrtl FIRRTL test exclude file] [--firrtl2verilog command to generate verilog from firrtl] verilog-files\n" >&2 + echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] [--xfirrtl FIRRTL test exclude file] [--firrtl2verilog command to generate verilog from firrtl] verilog-files\n" >&2 exit 1 esac done From 23148ffae14318bb34cb311eb13494e25ebf4593 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Feb 2019 18:40:11 +0100 Subject: [PATCH 43/53] Fixes related to handling of autowires and upto-ranges, fixes #814 Signed-off-by: Clifford Wolf --- frontends/ast/genrtlil.cc | 4 ++-- frontends/ast/simplify.cc | 17 ++++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index bdc34d490..2d591b29d 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -644,7 +644,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); - this_width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1; + this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; delete left_at_zero_ast; delete right_at_zero_ast; } else @@ -1034,7 +1034,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); - int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1; + int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 6ae62ead8..737fb300c 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -934,12 +934,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } if (current_scope.count(str) == 0) { - // log_warning("Creating auto-wire `%s' in module `%s'.\n", str.c_str(), current_ast_mod->str.c_str()); - AstNode *auto_wire = new AstNode(AST_AUTOWIRE); - auto_wire->str = str; - current_ast_mod->children.push_back(auto_wire); - current_scope[str] = auto_wire; - did_something = true; + if (flag_autowire) { + AstNode *auto_wire = new AstNode(AST_AUTOWIRE); + auto_wire->str = str; + current_ast_mod->children.push_back(auto_wire); + current_scope[str] = auto_wire; + did_something = true; + } else { + log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); + } } if (id2ast != current_scope[str]) { id2ast = current_scope[str]; @@ -1689,7 +1692,7 @@ skip_dynamic_range_lvalue_expansion:; while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); - int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1; + int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); From 893194689daee52ea870fef839c237c61e14c6c9 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Feb 2019 18:50:02 +0100 Subject: [PATCH 44/53] Fix typo in passes/pmgen/README.md Signed-off-by: Clifford Wolf --- passes/pmgen/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md index 27e54b43e..a1007dc62 100644 --- a/passes/pmgen/README.md +++ b/passes/pmgen/README.md @@ -65,7 +65,7 @@ list of variable names. For example: State variables are automatically managed by the generated backtracking algorithm and saved and restored as needed. -They are atomatically initialzed to the default constructed value of their type +They are automatically initialized to the default constructed value of their type when `.run(callback_function)` is called. Declaring udata variables From 4c82ddf39412fa7f90d71f259d578f98e732c865 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Thu, 21 Feb 2019 10:16:38 -0800 Subject: [PATCH 45/53] Add -params mode to force undef parameters in selected cells. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- passes/cmds/setundef.cc | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc index 56ef2d125..aea3165e4 100644 --- a/passes/cmds/setundef.cc +++ b/passes/cmds/setundef.cc @@ -143,6 +143,9 @@ struct SetundefPass : public Pass { log(" -init\n"); log(" also create/update init values for flip-flops\n"); log("\n"); + log(" -params\n"); + log(" replace undef in cell parameters\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { @@ -150,6 +153,7 @@ struct SetundefPass : public Pass { bool undriven_mode = false; bool expose_mode = false; bool init_mode = false; + bool params_mode = false; SetundefWorker worker; log_header(design, "Executing SETUNDEF pass (replace undef values with defined constants).\n"); @@ -199,6 +203,10 @@ struct SetundefPass : public Pass { init_mode = true; continue; } + if (args[argidx] == "-params") { + params_mode = true; + continue; + } if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) { got_value = true; worker.next_bit_mode = MODE_RANDOM; @@ -228,6 +236,27 @@ struct SetundefPass : public Pass { for (auto module : design->selected_modules()) { + if (params_mode) + { + for (auto *cell : module->cells()) + { + // Only modify selected cells. + if (!design->selected(module, it)) { + continue; + } + + for (auto ¶meter : cell->parameters) + { + for (auto &bit : parameter.second.bits) { + if (bit > RTLIL::State::S1) + { + bit = worker.next_bit(); + } + } + } + } + } + if (undriven_mode) { if (!module->processes.empty()) From d55790909c3b4244889d092c8eae630c7efd1aee Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Feb 2019 19:27:23 +0100 Subject: [PATCH 46/53] Hotfix for 4c82ddf Signed-off-by: Clifford Wolf --- passes/cmds/setundef.cc | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc index aea3165e4..f6949c820 100644 --- a/passes/cmds/setundef.cc +++ b/passes/cmds/setundef.cc @@ -238,20 +238,11 @@ struct SetundefPass : public Pass { { if (params_mode) { - for (auto *cell : module->cells()) - { - // Only modify selected cells. - if (!design->selected(module, it)) { - continue; - } - - for (auto ¶meter : cell->parameters) - { + for (auto *cell : module->selected_cells()) { + for (auto ¶meter : cell->parameters) { for (auto &bit : parameter.second.bits) { if (bit > RTLIL::State::S1) - { bit = worker.next_bit(); - } } } } From 362ef36ccdcb3023f9db259b983c08811f794edd Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Feb 2019 23:13:14 +0100 Subject: [PATCH 47/53] Fix Travis It looks like that whole "Fixing Travis's git clone" code was just there to make the "git describe --tags" work. I simply removed both. Signed-off-by: Clifford Wolf --- .travis/build-and-test.sh | 2 ++ .travis/setup.sh | 49 +++++++-------------------------------- Makefile | 2 +- 3 files changed, 11 insertions(+), 42 deletions(-) diff --git a/.travis/build-and-test.sh b/.travis/build-and-test.sh index 096dde64f..b8c35041d 100755 --- a/.travis/build-and-test.sh +++ b/.travis/build-and-test.sh @@ -36,6 +36,8 @@ echo ########################################################################## +./yosys tests/simple/fiedler-cooley.v + echo echo 'Testing...' && echo -en 'travis_fold:start:script.test\\r' echo diff --git a/.travis/setup.sh b/.travis/setup.sh index d689cd2bd..4af0b8ee9 100755 --- a/.travis/setup.sh +++ b/.travis/setup.sh @@ -6,48 +6,15 @@ source .travis/common.sh ########################################################################## -# Fixing Travis's git clone -echo -echo 'Fixing git setup...' && echo -en 'travis_fold:start:before_install.git\\r' -echo -git fetch --unshallow && git fetch --tags - -# For pull requests, we get more info about the git source. -if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then - echo "- Fetching from pull request source" - git remote add source https://github.com/$TRAVIS_PULL_REQUEST_SLUG.git - git fetch source && git fetch --tags - - echo "- Fetching the actual pull request" - git fetch origin pull/$TRAVIS_PULL_REQUEST/head:pull-$TRAVIS_PULL_REQUEST-head - git fetch origin pull/$TRAVIS_PULL_REQUEST/merge:pull-$TRAVIS_PULL_REQUEST-merge - - git log -n 5 --graph pull-$TRAVIS_PULL_REQUEST-merge -fi - -# For building branches we need to fix the "detached head" state. -if [ z"$TRAVIS_BRANCH" != z ]; then - TRAVIS_COMMIT_ACTUAL=$(git log --pretty=format:'%H' -n 1) - echo "- Fixing detached head (current $TRAVIS_COMMIT_ACTUAL -> $TRAVIS_COMMIT)" - git remote -v - git branch -v - if [ x"$(git show-ref -s HEAD)" = x"$TRAVIS_COMMIT" ]; then - echo "Checked out at $TRAVIS_COMMIT" - else - if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then - git fetch source $TRAVIS_COMMIT || echo "Unable to fetch $TRAVIS_COMMIT from source" - fi - git fetch origin $TRAVIS_COMMIT || echo "Unable to fetch $TRAVIS_COMMIT from origin" - fi - git branch -D $TRAVIS_BRANCH || true - git checkout $TRAVIS_COMMIT -b $TRAVIS_BRANCH - git branch -v -fi - # Output status information. -git status -git describe --tags -git log -n 5 --graph +( + set +e + set -x + git status + git branch -v + git log -n 5 --graph + git log --format=oneline -n 20 --graph +) echo echo -en 'travis_fold:end:before_install.git\\r' echo diff --git a/Makefile b/Makefile index d83a71256..8e93cd285 100644 --- a/Makefile +++ b/Makefile @@ -100,7 +100,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.8+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 4d4665b.. | wc -l; }) +YOSYS_VER := 0.8+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 4d4665b.. 2> /dev/null | wc -l; }) GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN) OBJS = kernel/version_$(GIT_REV).o From 25680f6a078bb32f157bd580705656496717bafb Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 22 Feb 2019 10:28:28 -0800 Subject: [PATCH 48/53] Fix WREDUCE on FF not fixing ARST_VALUE parameter. Adds test case that fails without code change. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- passes/opt/wreduce.cc | 13 +++++++++++++ tests/opt/opt_ff.v | 21 +++++++++++++++++++++ tests/opt/opt_ff.ys | 3 +++ 3 files changed, 37 insertions(+) create mode 100644 tests/opt/opt_ff.v create mode 100644 tests/opt/opt_ff.ys diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 3aa916ec2..c550b402e 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -195,6 +195,19 @@ struct WreduceWorker for (auto bit : sig_q) work_queue_bits.insert(bit); + // Narrow ARST_VALUE parameter to new size. + // + // Note: This works because earlier loop only removes signals from + // the upper bits of the DFF. + if(cell->parameters.count("\\ARST_VALUE") > 0) { + RTLIL::Const old_arst_value = cell->parameters.at("\\ARST_VALUE"); + std::vector new_arst_value(GetSize(sig_q)); + for(int i = 0; i < GetSize(sig_q); ++i) { + new_arst_value[i] = old_arst_value[i]; + } + cell->parameters["\\ARST_VALUE"] = RTLIL::Const(new_arst_value); + } + cell->setPort("\\D", sig_d); cell->setPort("\\Q", sig_q); cell->fixup_parameters(); diff --git a/tests/opt/opt_ff.v b/tests/opt/opt_ff.v new file mode 100644 index 000000000..a01b64b61 --- /dev/null +++ b/tests/opt/opt_ff.v @@ -0,0 +1,21 @@ +module top( + input clk, + input rst, + input [2:0] a, + output [1:0] b +); + reg [2:0] b_reg; + initial begin + b_reg <= 3'b0; + end + + assign b = b_reg[1:0]; + always @(posedge clk or posedge rst) begin + if(rst) begin + b_reg <= 3'b0; + end else begin + b_reg <= a; + end + end +endmodule + diff --git a/tests/opt/opt_ff.ys b/tests/opt/opt_ff.ys new file mode 100644 index 000000000..704c7acf3 --- /dev/null +++ b/tests/opt/opt_ff.ys @@ -0,0 +1,3 @@ +read_verilog opt_ff.v +synth_ice40 +ice40_unlut From 71bcc4c644b0dafa760ff8b6d7bd1109836be621 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Fri, 22 Feb 2019 16:06:10 -0800 Subject: [PATCH 49/53] Address requested changes - don't require non-$ name. Suppress warning if name does begin with a `$`. Fix hierachy tests so they have something to grep. Announce hierarchy test types. --- passes/hierarchy/hierarchy.cc | 14 +++++++------- tests/various/hierarchy.sh | 9 ++++++--- tests/various/run-test.sh | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index f112e969e..cb54ffa58 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -525,14 +525,14 @@ int find_top_mod_score(Design *design, Module *module, dict &db) celltype = basic_cell_type(celltype); } // Is this cell a module instance? - if (celltype[0] != '$') { - auto instModule = design->module(celltype); - // If there is no instance for this, issue a warning. - if (instModule == NULL) { + auto instModule = design->module(celltype); + // If there is no instance for this, issue a warning. + if (instModule == NULL) { + // but only if we're sure it is a reference to a module. + if (celltype[0] != '$') log_warning("find_top_mod_score: no instance for %s.%s\n", celltype.c_str(), cell->name.c_str()); - } else { - score = max(score, find_top_mod_score(design, instModule, db) + 1); - } + } else { + score = max(score, find_top_mod_score(design, instModule, db) + 1); } } db[module] = score; diff --git a/tests/various/hierarchy.sh b/tests/various/hierarchy.sh index dcb4dc056..d33a247be 100644 --- a/tests/various/hierarchy.sh +++ b/tests/various/hierarchy.sh @@ -3,7 +3,8 @@ set -e -../../yosys -q -s - <<- EOY 2>&1 | grep "Automatically selected TOP as design top module" +echo -n " TOP first - " +../../yosys -s - <<- EOY | grep "Automatically selected TOP as design top module" read_verilog << EOV module TOP(a, y); input a; @@ -21,7 +22,8 @@ set -e hierarchy -auto-top EOY -../../yosys -q -s - <<- EOY 2>&1 | grep "Automatically selected TOP as design top module" +echo -n " TOP last - " +../../yosys -s - <<- EOY | grep "Automatically selected TOP as design top module" read_verilog << EOV module aoi12(a, y); input a; @@ -39,7 +41,8 @@ EOY hierarchy -auto-top EOY -../../yosys -q -s - <<- EOY 2>&1 | grep "Automatically selected noTop as design top module." +echo -n " no explicit top - " +../../yosys -s - <<- EOY | grep "Automatically selected noTop as design top module." read_verilog << EOV module aoi12(a, y); input a; diff --git a/tests/various/run-test.sh b/tests/various/run-test.sh index 7cd1a8650..d49553ede 100755 --- a/tests/various/run-test.sh +++ b/tests/various/run-test.sh @@ -9,6 +9,6 @@ shell_tests=$(echo *.sh | sed -e 's/run-test.sh//') if [ "$shell_tests" ]; then for s in $shell_tests; do echo "Running $s.." - bash $s >& ${s%.sh}.log + bash $s done fi From a516b4fb5af0d8389fa8aede95ae5a76bec13dcf Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 24 Feb 2019 19:51:30 +0100 Subject: [PATCH 50/53] Check if Verific was built with DB_PRESERVE_INITIAL_VALUE Signed-off-by: Clifford Wolf --- frontends/verific/verific.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 94138cdd6..8ee951d20 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1920,6 +1920,10 @@ struct VerificPass : public Pass { // WARNING: instantiating unknown module 'XYZ' (VERI-1063) Message::SetMessageType("VERI-1063", VERIFIC_ERROR); +#ifndef DB_PRESERVE_INITIAL_VALUE +# warning Verific was built without DB_PRESERVE_INITIAL_VALUE. +#endif + set_verific_global_flags = false; } From 1816fe06af9ab2c50bd293dc10359238acc88f12 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 24 Feb 2019 20:09:41 +0100 Subject: [PATCH 51/53] Fix handling of defparam for when default_nettype is none Signed-off-by: Clifford Wolf --- frontends/ast/simplify.cc | 4 ++++ tests/simple/hierdefparam.v | 2 ++ 2 files changed, 6 insertions(+) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 737fb300c..46013544b 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -642,6 +642,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // (iterate by index as e.g. auto wires can add new children in the process) for (size_t i = 0; i < children.size(); i++) { bool did_something_here = true; + bool backup_flag_autowire = flag_autowire; if ((type == AST_GENFOR || type == AST_FOR) && i >= 3) break; if ((type == AST_GENIF || type == AST_GENCASE) && i >= 1) @@ -652,6 +653,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, break; if (type == AST_PREFIX && i >= 1) break; + if (type == AST_DEFPARAM && i == 0) + flag_autowire = true; while (did_something_here && i < children.size()) { bool const_fold_here = const_fold, in_lvalue_here = in_lvalue; int width_hint_here = width_hint; @@ -686,6 +689,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, children.erase(children.begin() + (i--)); did_something = true; } + flag_autowire = backup_flag_autowire; } for (auto &attr : attributes) { while (attr.second->simplify(true, false, false, stage, -1, false, true)) diff --git a/tests/simple/hierdefparam.v b/tests/simple/hierdefparam.v index ff92c38bd..c9368ca7a 100644 --- a/tests/simple/hierdefparam.v +++ b/tests/simple/hierdefparam.v @@ -1,3 +1,5 @@ +`default_nettype none + module hierdefparam_top(input [7:0] A, output [7:0] Y); generate begin:foo hierdefparam_a mod_a(.A(A), .Y(Y)); From cd722f26a5437e145c02c49b5736bd03b13927da Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 24 Feb 2019 20:34:23 +0100 Subject: [PATCH 52/53] Cleanups in ARST handling in wreduce Signed-off-by: Clifford Wolf --- passes/opt/wreduce.cc | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index c550b402e..09983bc67 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -196,16 +196,10 @@ struct WreduceWorker work_queue_bits.insert(bit); // Narrow ARST_VALUE parameter to new size. - // - // Note: This works because earlier loop only removes signals from - // the upper bits of the DFF. - if(cell->parameters.count("\\ARST_VALUE") > 0) { - RTLIL::Const old_arst_value = cell->parameters.at("\\ARST_VALUE"); - std::vector new_arst_value(GetSize(sig_q)); - for(int i = 0; i < GetSize(sig_q); ++i) { - new_arst_value[i] = old_arst_value[i]; - } - cell->parameters["\\ARST_VALUE"] = RTLIL::Const(new_arst_value); + if (cell->parameters.count("\\ARST_VALUE")) { + Const arst_value = cell->getParam("\\ARST_VALUE"); + arst_value.bits.resize(GetSize(sig_q)); + cell->setParam("\\ARST_VALUE", arst_value); } cell->setPort("\\D", sig_d); From c258b99040c8414952a3aceae874dc47563540dc Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 24 Feb 2019 20:41:36 +0100 Subject: [PATCH 53/53] Minor changes ontop of 71bcc4c: Remove hierarchy warning that is redundant to -check Signed-off-by: Clifford Wolf --- passes/hierarchy/hierarchy.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index cb54ffa58..2d8edebb5 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -527,11 +527,7 @@ int find_top_mod_score(Design *design, Module *module, dict &db) // Is this cell a module instance? auto instModule = design->module(celltype); // If there is no instance for this, issue a warning. - if (instModule == NULL) { - // but only if we're sure it is a reference to a module. - if (celltype[0] != '$') - log_warning("find_top_mod_score: no instance for %s.%s\n", celltype.c_str(), cell->name.c_str()); - } else { + if (instModule != nullptr) { score = max(score, find_top_mod_score(design, instModule, db) + 1); } }