diff --git a/flows/flows.bzl b/flows/flows.bzl index 80e5b43a..d0ed8642 100644 --- a/flows/flows.bzl +++ b/flows/flows.bzl @@ -215,6 +215,13 @@ def _run_step_with_inputs(ctx, step, inputs_dict, outputs_step_dict): return dicts.add(inputs_dict, outputs_dict) +def target_to_file(target): + all_files = target.files.to_list() + if len(all_files) != 1: + fail("Input target", target, "should provide exactly one file instead of", all_files) + + return all_files[0] + def _run_flow_impl(ctx): if len(ctx.attr.output_names) != len(ctx.outputs.output_files): fail( @@ -249,7 +256,9 @@ def _run_flow_impl(ctx): "lists should have the same length", ) - inputs_dict = dict(zip(ctx.attr.input_names, ctx.attr.input_files)) + input_files = [target_to_file(target) for target in ctx.attr.input_files] + + inputs_dict = dict(zip(ctx.attr.input_names, input_files)) for step in ctx.attr.flow: inputs_dict = _run_step_with_inputs(ctx, step, inputs_dict, outputs_step_dict) diff --git a/flows/tests/BUILD.bazel b/flows/tests/BUILD.bazel index ed0449c9..42e46c3a 100644 --- a/flows/tests/BUILD.bazel +++ b/flows/tests/BUILD.bazel @@ -14,6 +14,7 @@ # Modular hardware flow tests +load("@bazel_skylib//rules:build_test.bzl", "build_test") load("@bazel_skylib//rules:diff_test.bzl", "diff_test") load("//flows:flows.bzl", "flow_binary", "run_flow") load("//flows/place_and_route:build_defs.bzl", "openroad_step") @@ -58,3 +59,37 @@ flow_binary( "goodbye_openroad", ], ) + +run_flow( + name = "synth_sky130_adder", + constants = {"top": "adder"}, + flow = ["//flows/yosys:synth_sky130"], + input_files = ["verilog_adder.v"], + input_names = ["rtl"], + output_files = ["sky130_adder_test.v"], + output_names = ["netlist"], +) + +# TODO(amfv): This only tests that adding the clock period constant +# does not break synthesis. Figure out how to test that the clock +# period is actually used properly. +run_flow( + name = "synth_sky130_adder_with_clock_period", + constants = { + "clock_period_ps": "2000", + "top": "adder", + }, + flow = ["//flows/yosys:synth_sky130"], + input_files = ["verilog_adder.v"], + input_names = ["rtl"], + output_files = ["sky130_adder_with_clock_period_test.v"], + output_names = ["netlist"], +) + +build_test( + name = "synth_sky130_smoke", + targets = [ + ":synth_sky130_adder", + ":synth_sky130_adder_with_clock_period", + ], +) diff --git a/flows/tests/verilog_adder.v b/flows/tests/verilog_adder.v new file mode 100644 index 00000000..3ca319e5 --- /dev/null +++ b/flows/tests/verilog_adder.v @@ -0,0 +1,24 @@ +//Copyright 2021 Google LLC +// +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. + + +module adder( + input [7:0] x, + input [7:0] y, + input carry_in, + output carry_output_bit, + output [7:0] sum, +); + assign {carry_output_bit, sum} = x + y + carry_in; +endmodule diff --git a/flows/yosys/BUILD.bazel b/flows/yosys/BUILD.bazel new file mode 100644 index 00000000..0257cf21 --- /dev/null +++ b/flows/yosys/BUILD.bazel @@ -0,0 +1,40 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Yosys synthesis step for modular flows. + +load("@rules_pkg//:pkg.bzl", "pkg_tar") +load("//flows:flows.bzl", "flow_binary") +load("//flows/yosys:build_defs.bzl", "yosys_synth_file_step") + +package(default_visibility = ["//flows:__subpackages__"]) + +exports_files(["synth.tcl"]) + +yosys_synth_file_step( + name = "synth_sky130", + standard_cells = "@com_google_skywater_pdk_sky130_fd_sc_hd//:sky130_fd_sc_hd", +) + +flow_binary( + name = "synth_sky130_bin", + flow = ["synth_sky130"], +) + +pkg_tar( + name = "synth_sky130_pkg", + srcs = [":synth_sky130_bin"], + include_runfiles = True, + strip_prefix = "./", +) diff --git a/flows/yosys/build_defs.bzl b/flows/yosys/build_defs.bzl new file mode 100644 index 00000000..30ca14a1 --- /dev/null +++ b/flows/yosys/build_defs.bzl @@ -0,0 +1,97 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Reimplementing place-and-route using composable and externalizable pieces""" + +load("//flows:flows.bzl", "FlowStepInfo", "script_prefix") +load("//pdk:build_defs.bzl", "StandardCellInfo") + +def _yosys_synth_file_step_impl(ctx): + yosys_executable = ctx.attr._yosys.files_to_run.executable + yosys_runfiles = ctx.attr._yosys[DefaultInfo].default_runfiles + + yosys_wrapper = ctx.actions.declare_file(ctx.attr.name) + + standard_cells = ctx.attr.standard_cells[StandardCellInfo] + + liberty = standard_cells.default_corner.liberty + + synth_tcl = ctx.file.synth_tcl + + cell_runfiles = ctx.runfiles(files = [synth_tcl, liberty, yosys_wrapper]) + + yosys_args = [ + "-q", # quiet mode only errors printed to stderr + "-q", # second q don't print warnings + "-Q", # Don't print header + "-T", # Don't print footer + "-c ${RUNFILES}/" + synth_tcl.short_path, + ] + + commands = [script_prefix] + commands.append("export LIBERTY=${RUNFILES}/" + liberty.short_path) + + # TODO(amfv): Compute Yosys data environment variables properly instead of hardcoding them. + commands.extend([ + "export YOSYS_DATDIR=${RUNFILES}/../at_clifford_yosys/techlibs/", + "export ABC=${RUNFILES}/../edu_berkeley_abc/abc", + ]) + + exec_yosys = """{yosys} {args} "$@"\n""".format( + yosys = "${RUNFILES}/" + yosys_executable.short_path, + args = " ".join(yosys_args), + ) + + commands.append(exec_yosys) + + ctx.actions.write( + output = yosys_wrapper, + content = "\n".join(commands) + "\n", + is_executable = True, + ) + + return [ + FlowStepInfo( + inputs = ["rtl"], + outputs = ["netlist"], + constants = ["top"], # , "clock_period"], + executable_type = "yosys", + arguments = [], + ), + DefaultInfo( + executable = yosys_wrapper, + # TODO(amfv): Switch to runfiles.merge_all once our minimum Bazel version provides it. + runfiles = cell_runfiles.merge(yosys_runfiles), + ), + ] + +yosys_synth_file_step = rule( + implementation = _yosys_synth_file_step_impl, + attrs = { + "_yosys": attr.label( + default = Label("@at_clifford_yosys//:yosys"), + executable = True, + cfg = "exec", + ), + "standard_cells": attr.label( + doc = "Standard cells to use in yosys synthesis step", + providers = [StandardCellInfo], + ), + "synth_tcl": attr.label( + default = Label("//flows/yosys:synth.tcl"), + allow_single_file = True, + doc = "Tcl script controlling Yosys synthesis, using the Flow Step API environment variables", + ), + }, +) diff --git a/flows/yosys/synth.tcl b/flows/yosys/synth.tcl new file mode 100644 index 00000000..9ccd43e5 --- /dev/null +++ b/flows/yosys/synth.tcl @@ -0,0 +1,30 @@ +# Default Yosys synthesis tcl script for the yosys_synth_file_step rule. +# It can be replaced by a user-defined script by overriding the synth_tcl +# argument of that rule. + +yosys -import + +# read design +set input_rtl $::env(INPUT_RTL) +yosys read_verilog -sv -defer $input_rtl + +# generic synthesis +set top $::env(CONSTANT_TOP) +yosys synth -top $top + +# mapping to liberty +set liberty $::env(LIBERTY) +dfflibmap -liberty $liberty + +if { [info exists ::env(CONSTANT_CLOCK_PERIOD_PS) ] } { + abc -liberty $liberty -dff -g aig -D $::env(CONSTANT_CLOCK_PERIOD_PS) +} else { + abc -liberty $liberty -dff -g aig +} + +# write synthesized design +set output $::env(OUTPUT_NETLIST) +write_verilog $output + +# print stats +stat