6 from .hdl
import Signal
, Record
, Elaboratable
7 from .back
import rtlil
13 def _collect_modules(names
):
16 py_module_name
, py_class_name
= name
.rsplit(".", 1)
17 py_module
= importlib
.import_module(py_module_name
)
18 if py_class_name
== "*":
19 for py_class_name
in py_module
.__all
__:
20 py_class
= py_module
.__dict
__[py_class_name
]
21 if not issubclass(py_class
, Elaboratable
):
23 modules
["{}.{}".format(py_module_name
, py_class_name
)] = py_class
25 py_class
= py_module
.__dict
__[py_class_name
]
26 if not isinstance(py_class
, type) or not issubclass(py_class
, Elaboratable
):
27 raise TypeError("{}.{} is not a class inheriting from Elaboratable"
28 .format(py_module_name
, py_class_name
))
29 modules
[name
] = py_class
33 def _serve_yosys(modules
):
35 request_json
= sys
.stdin
.readline()
36 if not request_json
: break
37 request
= json
.loads(request_json
)
39 if request
["method"] == "modules":
40 response
= {"modules": list(modules
.keys())}
42 elif request
["method"] == "derive":
43 module_name
= request
["module"]
46 for parameter_name
, parameter
in request
["parameters"].items():
47 if parameter
["type"] == "unsigned":
48 parameter_value
= int(parameter
["value"], 2)
49 elif parameter
["type"] == "signed":
50 width
= len(parameter
["value"])
51 parameter_value
= int(parameter
["value"], 2)
52 if parameter_value
& (1 << (width
- 1)):
53 parameter_value
= -((1 << width
) - value
)
54 elif parameter
["type"] == "string":
55 parameter_value
= parameter
["value"]
56 elif parameter
["type"] == "real":
57 parameter_value
= float(parameter
["value"])
59 raise NotImplementedError("Unrecognized parameter type {}"
60 .format(parameter_name
))
61 if parameter_name
.startswith("$"):
62 index
= int(parameter_name
[1:])
63 while len(args
) < index
:
65 args
[index
] = parameter_value
66 if parameter_name
.startswith("\\"):
67 kwargs
[parameter_name
[1:]] = parameter_value
70 elaboratable
= modules
[module_name
](*args
, **kwargs
)
72 # By convention, any public attribute that is a Signal or a Record is
74 for port_name
, port
in vars(elaboratable
).items():
75 if not port_name
.startswith("_") and isinstance(port
, (Signal
, Record
)):
76 ports
+= port
._lhs
_signals
()
77 rtlil_text
= rtlil
.convert(elaboratable
, name
=module_name
, ports
=ports
)
78 response
= {"frontend": "ilang", "source": rtlil_text
}
79 except Exception as error
:
80 response
= {"error": "{}: {}".format(type(error
).__name
__, str(error
))}
83 return {"error": "Unrecognized method {!r}".format(request
["method"])}
85 sys
.stdout
.write(json
.dumps(response
))
86 sys
.stdout
.write("\n")
91 parser
= argparse
.ArgumentParser(description
=r
"""
92 The nMigen RPC server allows a HDL synthesis program to request an nMigen module to
93 be elaborated on demand using the parameters it provides. For example, using Yosys together
94 with the nMigen RPC server allows instantiating parametric nMigen modules directly
97 def add_modules_arg(parser
):
98 parser
.add_argument("modules", metavar
="MODULE", type=str, nargs
="+",
99 help="import and provide MODULES")
100 protocols
= parser
.add_subparsers(metavar
="PROTOCOL", dest
="protocol", required
=True)
101 protocol_yosys
= protocols
.add_parser("yosys", help="use Yosys JSON-based RPC protocol")
102 add_modules_arg(protocol_yosys
)
104 args
= parser
.parse_args()
105 modules
= _collect_modules(args
.modules
)
106 if args
.protocol
== "yosys":
107 _serve_yosys(modules
)
110 if __name__
== "__main__":