Progress in pmgen
authorClifford Wolf <clifford@clifford.at>
Sun, 13 Jan 2019 09:57:11 +0000 (10:57 +0100)
committerClifford Wolf <clifford@clifford.at>
Tue, 15 Jan 2019 10:23:25 +0000 (11:23 +0100)
Signed-off-by: Clifford Wolf <clifford@clifford.at>
passes/pmgen/.gitignore [new file with mode: 0644]
passes/pmgen/Makefile.inc [new file with mode: 0644]
passes/pmgen/ice40_dsp.cc [new file with mode: 0644]
passes/pmgen/ice40_dsp.pmg
passes/pmgen/pmgen.py [new file with mode: 0644]

diff --git a/passes/pmgen/.gitignore b/passes/pmgen/.gitignore
new file mode 100644 (file)
index 0000000..c926305
--- /dev/null
@@ -0,0 +1 @@
+/ice40_dsp_pm.h
diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc
new file mode 100644 (file)
index 0000000..33baaca
--- /dev/null
@@ -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 (file)
index 0000000..0498f31
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *
+ *  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<std::string> 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
index 5a0af3e04fb77fd6c043bf115e4cc403c439a4ff..2b9bb8783f217a6b19d8609c05f7bc3c2e2f81b8 100644 (file)
@@ -1,6 +1,6 @@
-state SigBit clock
-state bool clock_pol, clock_vld
-state SigSpec sigA, sigB, sigY
+state <SigBit> clock
+state <bool> clock_pol clock_vld
+state <SigSpec> 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 <SigSpec> 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 <SigSpec> 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 <SigSpec> 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 (file)
index 0000000..bf70a6d
--- /dev/null
@@ -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<void(struct {}_pm*)> 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_{}_key_type, vector<Cell*>> index_{};".format(index, index), file=f)
+    print("  pool<Cell*> 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<void(struct {}_pm*)> 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)