diff options
author | whitequark <whitequark@whitequark.org> | 2019-09-26 03:57:16 +0000 |
---|---|---|
committer | whitequark <whitequark@whitequark.org> | 2019-09-30 15:53:11 +0000 |
commit | 99a7f39084cf4b9cd21e2a1e4f4a842993dfd147 (patch) | |
tree | 805a7ac04968e138c6759e2fa13b2bc560309b11 /tests | |
parent | 8f2bdff7b9f948141dfb00a337f9c2acec6b118e (diff) | |
download | yosys-99a7f39084cf4b9cd21e2a1e4f4a842993dfd147.tar.gz yosys-99a7f39084cf4b9cd21e2a1e4f4a842993dfd147.tar.bz2 yosys-99a7f39084cf4b9cd21e2a1e4f4a842993dfd147.zip |
rpc: new frontend.
A new pass, connect_rpc, allows any HDL frontend that can read/write
JSON from/to stdin/stdout or an unix socket or a named pipe to
participate in elaboration as a first class citizen, such that any
other HDL supported by Yosys directly or indirectly can transparently
instantiate modules handled by this frontend.
Recognizing that many HDL frontends emit Verilog, it allows the RPC
frontend to direct Yosys to process the result of instantiation via
any built-in Yosys frontend. The resulting RTLIL is then hygienically
integrated into the overall design.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/rpc/.gitignore | 1 | ||||
-rw-r--r-- | tests/rpc/design.v | 8 | ||||
-rw-r--r-- | tests/rpc/exec.ys | 5 | ||||
-rw-r--r-- | tests/rpc/frontend.py | 126 | ||||
-rwxr-xr-x | tests/rpc/run-test.sh | 6 | ||||
-rw-r--r-- | tests/rpc/unix.ys | 6 |
6 files changed, 152 insertions, 0 deletions
diff --git a/tests/rpc/.gitignore b/tests/rpc/.gitignore new file mode 100644 index 000000000..397b4a762 --- /dev/null +++ b/tests/rpc/.gitignore @@ -0,0 +1 @@ +*.log diff --git a/tests/rpc/design.v b/tests/rpc/design.v new file mode 100644 index 000000000..80f1dac1a --- /dev/null +++ b/tests/rpc/design.v @@ -0,0 +1,8 @@ +module top(input [3:0] i, output [3:0] o); + python_inv #( + .width(4) + ) inv ( + .i(i), + .o(o), + ); +endmodule diff --git a/tests/rpc/exec.ys b/tests/rpc/exec.ys new file mode 100644 index 000000000..b46009fb9 --- /dev/null +++ b/tests/rpc/exec.ys @@ -0,0 +1,5 @@ +connect_rpc -exec python3 frontend.py stdio +read_verilog design.v +hierarchy -top top +flatten +select -assert-count 1 t:$neg diff --git a/tests/rpc/frontend.py b/tests/rpc/frontend.py new file mode 100644 index 000000000..eff41738a --- /dev/null +++ b/tests/rpc/frontend.py @@ -0,0 +1,126 @@ +def modules(): + return ["python_inv"] + +def derive(module, parameters): + assert module == r"python_inv" + if parameters.keys() != {r"\width"}: + raise ValueError("Invalid parameters") + return "ilang", r""" +module \impl + wire width {width:d} input 1 \i + wire width {width:d} output 2 \o + cell $neg $0 + parameter \A_SIGNED 1'0 + parameter \A_WIDTH 32'{width:b} + parameter \Y_WIDTH 32'{width:b} + connect \A \i + connect \Y \o + end +end +module \python_inv + wire width {width:d} input 1 \i + wire width {width:d} output 2 \o + cell \impl $0 + connect \i \i + connect \o \o + end +end +""".format(width=parameters[r"\width"]) + +# ---------------------------------------------------------------------------- + +import json +import argparse +import sys, socket, os +try: + import msvcrt, win32pipe, win32file +except ImportError: + msvcrt = win32pipe = win32file = None + +def map_parameter(parameter): + if parameter["type"] == "unsigned": + return int(parameter["value"], 2) + if parameter["type"] == "signed": + width = len(parameter["value"]) + value = int(parameter["value"], 2) + if value & (1 << (width - 1)): + value = -((1 << width) - value) + return value + if parameter["type"] == "string": + return parameter["value"] + if parameter["type"] == "real": + return float(parameter["value"]) + +def call(input_json): + input = json.loads(input_json) + if input["method"] == "modules": + return json.dumps({"modules": modules()}) + if input["method"] == "derive": + try: + frontend, source = derive(input["module"], + {name: map_parameter(value) for name, value in input["parameters"].items()}) + return json.dumps({"frontend": frontend, "source": source}) + except ValueError as e: + return json.dumps({"error": str(e)}) + +def main(): + parser = argparse.ArgumentParser() + modes = parser.add_subparsers(dest="mode") + mode_stdio = modes.add_parser("stdio") + if os.name == "posix": + mode_path = modes.add_parser("unix-socket") + if os.name == "nt": + mode_path = modes.add_parser("named-pipe") + mode_path.add_argument("path") + args = parser.parse_args() + + if args.mode == "stdio": + while True: + input = sys.stdin.readline() + if not input: break + sys.stdout.write(call(input) + "\n") + sys.stdout.flush() + + if args.mode == "unix-socket": + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.bind(args.path) + try: + sock.listen(1) + conn, addr = sock.accept() + file = conn.makefile("rw") + while True: + input = file.readline() + if not input: break + file.write(call(input) + "\n") + file.flush() + finally: + sock.close() + os.unlink(args.path) + + if args.mode == "named-pipe": + pipe = win32pipe.CreateNamedPipe(args.path, win32pipe.PIPE_ACCESS_DUPLEX, + win32pipe.PIPE_TYPE_BYTE|win32pipe.PIPE_READMODE_BYTE|win32pipe.PIPE_WAIT, + 1, 4096, 4096, 0, None) + win32pipe.ConnectNamedPipe(pipe, None) + try: + while True: + input = b"" + while not input.endswith(b"\n"): + result, data = win32file.ReadFile(pipe, 4096) + assert result == 0 + input += data + assert not b"\n" in input or input.endswith(b"\n") + output = (call(input.decode("utf-8")) + "\n").encode("utf-8") + length = len(output) + while length > 0: + result, done = win32file.WriteFile(pipe, output) + assert result == 0 + length -= done + except win32file.error as e: + if e.args[0] == 109: # ERROR_BROKEN_PIPE + pass + else: + raise + +if __name__ == "__main__": + main() diff --git a/tests/rpc/run-test.sh b/tests/rpc/run-test.sh new file mode 100755 index 000000000..44ce7e674 --- /dev/null +++ b/tests/rpc/run-test.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -e +for x in *.ys; do + echo "Running $x.." + ../../yosys -ql ${x%.ys}.log $x +done diff --git a/tests/rpc/unix.ys b/tests/rpc/unix.ys new file mode 100644 index 000000000..cc7ec14ab --- /dev/null +++ b/tests/rpc/unix.ys @@ -0,0 +1,6 @@ +!python3 frontend.py unix-socket frontend.sock & sleep 0.1 +connect_rpc -path frontend.sock +read_verilog design.v +hierarchy -top top +flatten +select -assert-count 1 t:$neg |