| OPENLANE_TAG ?= 2022.02.23_02.50.41 |
| OPENLANE_IMAGE_NAME ?= efabless/openlane:$(OPENLANE_TAG) |
| export PDK ?= sky130A |
| export RCX_CORNER ?= nom |
| export LIB_CORNER ?= t |
| export ALLOW_MISSING_SPEF ?= 1 |
| export PDK_REF_PATH = $(PDK_ROOT)/$(PDK)/libs.ref/ |
| export PDK_TECH_PATH = $(PDK_ROOT)/$(PDK)/libs.tech/ |
| export PROJECT_ROOT ?= $(CARAVEL_ROOT) |
| |
| logs-dir = $(PROJECT_ROOT)/logs |
| logs = $(logs-dir)/rcx $(logs-dir)/sdf $(logs-dir)/top $(logs-dir)/sta |
| $(logs): |
| mkdir -p $@ |
| |
| SPEF_OVERWRITE ?= "" |
| define docker_run_base |
| docker run \ |
| --rm \ |
| -e PROJECT_ROOT=$(PROJECT_ROOT) \ |
| -e BLOCK=$1 \ |
| -e PDK=$(PDK) \ |
| -e LIB_CORNER=$(LIB_CORNER) \ |
| -e RCX_CORNER=$(RCX_CORNER) \ |
| -e MCW_ROOT=$(MCW_ROOT) \ |
| -e SPEF_OVERWRITE=$(SPEF_OVERWRITE) \ |
| -e CUP_ROOT=$(CUP_ROOT) \ |
| -e CARAVEL_ROOT=$(CARAVEL_ROOT) \ |
| -e TIMING_ROOT=$(TIMING_ROOT) \ |
| -e PDK_REF_PATH=$(PDK_ROOT)/$(PDK)/libs.ref/ \ |
| -e PDK_TECH_PATH=$(PDK_ROOT)/$(PDK)/libs.tech/ \ |
| -e ALLOW_MISSING_SPEF=$(ALLOW_MISSING_SPEF) \ |
| -v $(PDK_ROOT):$(PDK_ROOT) \ |
| -v $(CUP_ROOT):$(CUP_ROOT) \ |
| -v $(MCW_ROOT):$(MCW_ROOT) \ |
| -v $(TIMING_ROOT):$(TIMING_ROOT) \ |
| -v $(CARAVEL_ROOT):$(CARAVEL_ROOT) \ |
| -v $(HOME):$(HOME) \ |
| -u $(shell id -u $(USER)):$(shell id -g $(USER)) \ |
| $(OPENLANE_IMAGE_NAME) |
| endef |
| |
| |
| define docker_run_sta |
| $(call docker_run_base,$1) \ |
| bash -c "set -eo pipefail && sta -exit $(TIMING_ROOT)/scripts/openroad/sta-$*.tcl \ |
| |& tee $(logs-dir)/sta/$*-$(RCX_CORNER)-$(LIB_CORNER).log" |
| @echo "logged to $(logs-dir)/sta/$*-$(RCX_CORNER)-$(LIB_CORNER).log" |
| endef |
| |
| define docker_run_sdf |
| $(call docker_run_base,$1) \ |
| bash -c "set -eo pipefail && openroad -exit $(TIMING_ROOT)/scripts/openroad/sdf.tcl \ |
| |& tee $(logs-dir)/sdf/$*-$(RCX_CORNER)-$(LIB_CORNER).log" |
| @echo "logged to $(logs-dir)/sdf/$*-$(RCX_CORNER)-$(LIB_CORNER).log" |
| endef |
| |
| define docker_run_rcx |
| $(call docker_run_base,$1) \ |
| bash -c "set -eo pipefail && openroad -exit $(TIMING_ROOT)/scripts/openroad/rcx.tcl \ |
| |& tee $(logs-dir)/rcx/$*-$(RCX_CORNER)-$(LIB_CORNER).log" |
| @echo "logged to $(logs-dir)/rcx/$*-$(RCX_CORNER)-$(LIB_CORNER).log" |
| endef |
| |
| blocks = $(shell cd $(CARAVEL_ROOT)/openlane && find * -maxdepth 0 -type d) |
| blocks := $(subst user_project_wrapper,,$(blocks)) |
| ifneq ($(CARAVEL_ROOT),$(MCW_ROOT)) |
| blocks += $(shell cd $(MCW_ROOT)/openlane && find * -maxdepth 0 -type d) |
| endif |
| ifneq ($(CARAVEL_ROOT),$(CUP_ROOT)) |
| blocks += $(shell cd $(CUP_ROOT)/openlane && find * -maxdepth 0 -type d) |
| endif |
| |
| # we don't have user_id_programming.def) |
| # mgmt_protect_hvl use hvl library which we don't handle yet |
| blocks := $(subst mgmt_protect_hvl,,$(blocks)) |
| blocks := $(subst chip_io_alt,,$(blocks)) |
| blocks := $(subst user_id_programming,,$(blocks)) |
| blocks := $(subst user_analog_project_wrapper,,$(blocks)) |
| blocks := $(subst caravan,,$(blocks)) |
| |
| defs = $(shell cd $(CARAVEL_ROOT)/def && find *.def -maxdepth 0 -type f ! -name 'user_project_wrapper.def') |
| ifneq ($(CARAVEL_ROOT),$(MCW_ROOT)) |
| defs += $(shell cd $(MCW_ROOT)/def && find *.def -maxdepth 0 -type f) |
| endif |
| ifneq ($(CARAVEL_ROOT),$(CUP_ROOT)) |
| defs += $(shell cd $(CUP_ROOT)/def && find *.def -maxdepth 0 -type f) |
| endif |
| |
| rcx-blocks = $(defs:%.def=rcx-%) |
| rcx-blocks-nom = $(blocks:%=rcx-%-nom) |
| rcx-blocks-max = $(blocks:%=rcx-%-max) |
| rcx-blocks-min = $(blocks:%=rcx-%-min) |
| rcx-blocks-t = $(blocks:%=rcx-%-t) |
| rcx-blocks-f = $(blocks:%=rcx-%-f) |
| rcx-blocks-s = $(blocks:%=rcx-%-s) |
| |
| sdf-blocks = $(blocks:%=sdf-%) |
| sdf-blocks-t = $(blocks:%=sdf-%-t) |
| sdf-blocks-f = $(blocks:%=sdf-%-f) |
| sdf-blocks-s = $(blocks:%=sdf-%-s) |
| sdf-blocks-nom = $(blocks:%=sdf-%-nom) |
| sdf-blocks-min = $(blocks:%=sdf-%-min) |
| sdf-blocks-max = $(blocks:%=sdf-%-max) |
| |
| $(sdf-blocks): sdf-%: |
| $(MAKE) -f timing.mk sdf-$*-nom |
| $(MAKE) -f timing.mk sdf-$*-min |
| $(MAKE) -f timing.mk sdf-$*-max |
| |
| $(sdf-blocks-nom): export RCX_CORNER = nom |
| $(sdf-blocks-min): export RCX_CORNER = min |
| $(sdf-blocks-max): export RCX_CORNER = max |
| $(sdf-blocks-nom): sdf-%-nom: sdf-%-t sdf-%-f sdf-%-s |
| $(sdf-blocks-min): sdf-%-min: sdf-%-t sdf-%-f sdf-%-s |
| $(sdf-blocks-max): sdf-%-max: sdf-%-t sdf-%-f sdf-%-s |
| |
| $(sdf-blocks-t): export LIB_CORNER = t |
| $(sdf-blocks-s): export LIB_CORNER = s |
| $(sdf-blocks-f): export LIB_CORNER = f |
| $(sdf-blocks-t): sdf-%-t: |
| $(call docker_run_sdf,$*) |
| $(sdf-blocks-s): sdf-%-s: |
| $(call docker_run_sdf,$*) |
| $(sdf-blocks-f): sdf-%-f: |
| $(call docker_run_sdf,$*) |
| |
| |
| sta-blocks = $(blocks:%=sta-%) |
| sta-blocks-t = $(blocks:%=sta-%-t) |
| sta-blocks-f = $(blocks:%=sta-%-f) |
| sta-blocks-s = $(blocks:%=sta-%-s) |
| sta-blocks-nom = $(blocks:%=sta-%-nom) |
| sta-blocks-min = $(blocks:%=sta-%-min) |
| sta-blocks-max = $(blocks:%=sta-%-max) |
| |
| $(sta-blocks): sta-%: |
| $(MAKE) -f timing.mk sta-$*-nom |
| $(MAKE) -f timing.mk sta-$*-min |
| $(MAKE) -f timing.mk sta-$*-max |
| |
| $(sta-blocks-nom): export RCX_CORNER = nom |
| $(sta-blocks-min): export RCX_CORNER = min |
| $(sta-blocks-max): export RCX_CORNER = max |
| $(sta-blocks-nom): sta-%-nom: sta-%-t sta-%-f sta-%-s |
| $(sta-blocks-min): sta-%-min: sta-%-t sta-%-f sta-%-s |
| $(sta-blocks-max): sta-%-max: sta-%-t sta-%-f sta-%-s |
| |
| $(sta-blocks-t): export LIB_CORNER = t |
| $(sta-blocks-s): export LIB_CORNER = s |
| $(sta-blocks-f): export LIB_CORNER = f |
| $(sta-blocks-t): sta-%-t: $(logs-dir)/sta |
| $(call docker_run_sta,$*) |
| $(sta-blocks-s): sta-%-s: |
| $(call docker_run_sta,$*) |
| $(sta-blocks-f): sta-%-f: |
| $(call docker_run_sta,$*) |
| |
| |
| $(rcx-blocks): rcx-%: $(rcx-requirements) |
| $(MAKE) -f timing.mk rcx-$*-nom & |
| $(MAKE) -f timing.mk rcx-$*-min & |
| $(MAKE) -f timing.mk rcx-$*-max |
| |
| $(rcx-blocks-nom): export RCX_CORNER = nom |
| $(rcx-blocks-min): export RCX_CORNER = min |
| $(rcx-blocks-max): export RCX_CORNER = max |
| $(rcx-blocks-nom): rcx-%-nom: rcx-%-t |
| $(rcx-blocks-min): rcx-%-min: rcx-%-t |
| $(rcx-blocks-max): rcx-%-max: rcx-%-t |
| |
| $(rcx-blocks-t): export LIB_CORNER = t |
| $(rcx-blocks-s): export LIB_CORNER = s |
| $(rcx-blocks-f): export LIB_CORNER = f |
| $(rcx-blocks-t): rcx-%-t: $(logs-dir)/rcx |
| $(call docker_run_rcx,$*) |
| $(rcx-blocks-s): rcx-%-s: |
| $(call docker_run_rcx,$*) |
| $(rcx-blocks-f): rcx-%-f: |
| $(call docker_run_rcx,$*) |
| |
| |
| define docker_run_caravel_timing |
| $(call docker_run_base,caravel) \ |
| bash -c "set -eo pipefail && sta -no_splash -exit $(TIMING_ROOT)/scripts/openroad/timing_top.tcl |& tee \ |
| $(logs-dir)/top/caravel-timing-$$(basename $(LIB_CORNER))-$(RCX_CORNER).log" |
| @echo "logged to $(logs-dir)/top/caravel-timing-$$(basename $(LIB_CORNER))-$(RCX_CORNER).log" |
| endef |
| |
| |
| caravel-timing-typ-targets = caravel-timing-typ-nom |
| caravel-timing-typ-targets += caravel-timing-typ-min |
| caravel-timing-typ-targets += caravel-timing-typ-max |
| |
| caravel-timing-slow-targets = caravel-timing-slow-nom |
| caravel-timing-slow-targets += caravel-timing-slow-min |
| caravel-timing-slow-targets += caravel-timing-slow-max |
| |
| caravel-timing-fast-targets = caravel-timing-fast-nom |
| caravel-timing-fast-targets += caravel-timing-fast-min |
| caravel-timing-fast-targets += caravel-timing-fast-max |
| |
| caravel-timing-targets = $(caravel-timing-slow-targets) |
| caravel-timing-targets += $(caravel-timing-fast-targets) |
| caravel-timing-targets += $(caravel-timing-typ-targets) |
| |
| .PHONY: caravel-timing-typ |
| $(caravel-timing-typ-targets): export LIB_CORNER = t |
| caravel-timing-typ: caravel-timing-typ-nom caravel-timing-typ-min caravel-timing-typ-max |
| |
| .PHONY: caravel-timing-typ-nom |
| .PHONY: caravel-timing-typ-min |
| .PHONY: caravel-timing-typ-max |
| caravel-timing-typ-nom: export RCX_CORNER = nom |
| caravel-timing-typ-min: export RCX_CORNER = min |
| caravel-timing-typ-max: export RCX_CORNER = max |
| |
| .PHONY: caravel-timing-slow |
| $(caravel-timing-slow-targets): export LIB_CORNER = s |
| caravel-timing-slow: caravel-timing-slow-nom caravel-timing-slow-min caravel-timing-slow-max |
| |
| .PHONY: caravel-timing-slow-nom |
| .PHONY: caravel-timing-slow-min |
| .PHONY: caravel-timing-slow-max |
| caravel-timing-slow-nom: export RCX_CORNER = nom |
| caravel-timing-slow-min: export RCX_CORNER = min |
| caravel-timing-slow-max: export RCX_CORNER = max |
| |
| .PHONY: caravel-timing-fast |
| $(caravel-timing-fast-targets): export LIB_CORNER = f |
| caravel-timing-fast: caravel-timing-fast-nom caravel-timing-fast-min caravel-timing-fast-max |
| |
| .PHONY: caravel-timing-fast-nom |
| .PHONY: caravel-timing-fast-min |
| .PHONY: caravel-timing-fast-max |
| caravel-timing-fast-nom: export RCX_CORNER = nom |
| caravel-timing-fast-min: export RCX_CORNER = min |
| caravel-timing-fast-max: export RCX_CORNER = max |
| |
| $(caravel-timing-targets): $(logs-dir)/top |
| $(call docker_run_caravel_timing) |
| |
| |
| # some useful dev double checking |
| # |
| rcx-requirements = $(CARAVEL_ROOT)/def/%.def |
| rcx-requirements += $(CARAVEL_ROOT)/lef/%.lef |
| rcx-requirements += $(CARAVEL_ROOT)/sdc/%.sdc |
| rcx-requirements += $(CARAVEL_ROOT)/verilog/gl/%.v |
| |
| exceptions = $(MCW_ROOT)/lef/caravel.lef |
| exceptions += $(MCW_ROOT)/lef/caravan.lef |
| # lets ignore these for now |
| exceptions += $(MCW_ROOT)/sdc/user_analog_project_wrapper.sdc |
| exceptions += $(MCW_ROOT)/sdc/user_project_wrapper.sdc |
| exceptions += $(MCW_ROOT)/verilog/gl/user_analog_project_wrapper.v |
| exceptions += $(MCW_ROOT)/verilog/gl/user_project_wrapper.v |
| |
| .PHONY: list-rcx |
| .PHONY: list-sdf |
| .PHONY: rcx-all |
| list-rcx: |
| @blocks="$(rcx-blocks)";\ |
| for block in $${blocks}; do echo "$$block"; done |
| list-sdf: |
| @echo $(sdf-blocks) |
| list-sta: |
| @echo $(sta-blocks) |
| rcx-all: $(rcx-blocks) |
| |
| $(exceptions): |
| $(warning we don't need lefs for $@ but take note anyway) |
| |
| $(CARAVEL_ROOT)/def/%.def: $(MCW_ROOT)/def/%.def ; |
| $(MCW_ROOT)/def/%.def: $(CUP_ROOT)/def/%.def ; |
| $(CUP_ROOT)/def/%.def: |
| $(error error if you are here it probably means that $@.def is mising from mcw and caravel) |
| |
| $(CARAVEL_ROOT)/lef/%.lef: $(MCW_ROOT)/lef/%.lef ; |
| $(MCW_ROOT)/lef/%.lef: $(CUP_ROOT)/lef/%.lef ; |
| $(CUP_ROOT)/lef/%.lef: |
| $(error error if you are here it probably means that $@.lef is mising from mcw and caravel) |
| |
| $(CARAVEL_ROOT)/sdc/%.sdc: $(MCW_ROOT)/sdc/%.sdc ; |
| $(MCW_ROOT)/sdc/%.sdc: $(CUP_ROOT)/sdc/%.sdc ; |
| $(CUP_ROOT)/sdc/%.sdc: |
| $(error error if you are here it probably means that $@.sdc is mising from mcw and caravel) |
| |
| $(CARAVEL_ROOT)/verilog/gl/%.v: $(MCW_ROOT)/verilog/gl/%.v ; |
| $(MCW_ROOT)/verilog/gl/%.v: $(CUP_ROOT)/verilog/gl/%.v ; |
| $(CUP_ROOT)/verilog/gl/%.v: |
| $(error error if you are here it probably means that gl/$@.v is mising from mcw and caravel) |
| |
| check_defined = \ |
| $(strip $(foreach 1,$1, \ |
| $(call __check_defined,$1,$(strip $(value 2))))) |
| __check_defined = \ |
| $(if $(value $1),, \ |
| $(error Undefined $1$(if $2, ($2)))) |
| |
| $(call check_defined, \ |
| MCW_ROOT \ |
| CUP_ROOT \ |
| PDK_ROOT \ |
| CARAVEL_ROOT \ |
| TIMING_ROOT \ |
| ) |