yosys/passes/pmgen/pmgen.py

263 lines
7.6 KiB
Python
Raw Normal View History

#!/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)